小ネタです。
ある場面において、プロセスの優先順位*1 を変更する機会があるかと思います。
そんな時、良く紹介されているのは、 タスクマネージャーからの優先度の変更ですね。
しかし、長時間のプロセス、かつ処理ごとにプロセスが立ち上がり直す場合には、やってられません。
ということで、PowerShell で変更する方法を見てみましょう。
目次
プロセスの取得
まずは、プロセスを取得してみましょう。
Get-Process
*2で見てみましょう。
Get-Process -Name powershell | select *
どばーってでましたが、大事なのはPriorityClassです。
PriorityClass : Normal
全体
__NounName : Process Name : powershell Handles : 441 VM : 649650176 WS : 81375232 PM : 72654848 NPM : 26200 Path : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe Company : Microsoft Corporation CPU : 1.96875 FileVersion : 6.3.9600.16384 (winblue_rtm.130821-1623) ProductVersion : 6.3.9600.16384 Description : Windows PowerShell Product : MicrosoftR WindowsR Operating System Id : 10412 PriorityClass : Normal HandleCount : 441 WorkingSet : 81375232 PagedMemorySize : 72654848 PrivateMemorySize : 72654848 VirtualMemorySize : 649650176 TotalProcessorTime : 00:00:01.9687500 BasePriority : 8 ExitCode : HasExited : False ExitTime : Handle : 4488 MachineName : . MainWindowHandle : 525428 MainWindowTitle : Windows PowerShell MainModule : System.Diagnostics.ProcessModule (powershell.exe) MaxWorkingSet : 1413120 MinWorkingSet : 204800 Modules : {System.Diagnostics.ProcessModule (powershell.exe), System.Diagnostics.ProcessModule (ntdll.dll), System.Diagnostics.ProcessModule (K ERNEL32.DLL), System.Diagnostics.ProcessModule (KERNELBASE.dll)...} NonpagedSystemMemorySize : 26200 NonpagedSystemMemorySize64 : 26200 PagedMemorySize64 : 72654848 PagedSystemMemorySize : 449832 PagedSystemMemorySize64 : 449832 PeakPagedMemorySize : 86937600 PeakPagedMemorySize64 : 86937600 PeakWorkingSet : 94642176 PeakWorkingSet64 : 94642176 PeakVirtualMemorySize : 669585408 PeakVirtualMemorySize64 : 669585408 PriorityBoostEnabled : True PrivateMemorySize64 : 72654848 PrivilegedProcessorTime : 00:00:00.4218750 ProcessName : powershell ProcessorAffinity : 255 Responding : True SessionId : 1 StartInfo : System.Diagnostics.ProcessStartInfo StartTime : 2014/02/12 4:37:15 SynchronizingObject : Threads : {7776, 9344, 1704, 13264...} UserProcessorTime : 00:00:01.5468750 VirtualMemorySize64 : 649650176 EnableRaisingEvents : False StandardInput : StandardOutput : StandardError : WorkingSet64 : 81375232 Site : Container :
PriorityClass を設定する
単純に、タスクマネージャーで表示される優先度をセットすればokです。
$ps = Get-Process -Name powershell $ps.PriorityClass = "High"
これで、優先度は変更されます。
さて、もう少し良く見てみましょう。
Get-Process -Name powershell | select PriorityClass | Get-Member
ということで、 NoteProperty ですね。
TypeName: Selected.System.Diagnostics.Process Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() PriorityClass NoteProperty System.Diagnostics.ProcessPriorityClass PriorityClass=Normal
ご存知の通り、[System.Diagnostics.ProcessPriorityClass] はEnumです。
[System.Diagnostics.ProcessPriorityClass]
IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True ProcessPriorityClass System.Enum
で、設定可能な定義が入っていると。
[Enum]::GetNames([System.Diagnostics.ProcessPriorityClass])
Normal Idle High RealTime BelowNormal AboveNormal
ここまでわかっていれば、さくっとファンクションにします。
コード
GitHub においておきます。
全文です。
function Set-ProcessPriorityClass { [CmdletBinding()] param ( [parameter( mandatory, position = 0, valueFromPipeline, valueFromPipelineByPropertyName)] [string[]] $Name, [parameter( mandatory = 0, position = 1, valueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [System.Diagnostics.ProcessPriorityClass] $Priority, [parameter( mandatory = 0, position = 2)] [switch] $WhatIf ) begin { DATA message { ConvertFrom-StringData ` " PriorityNotChange = Process Name '{0}' Priority '{1}' was already same as Priority '{2}' you set. Skip priority change. PriorityChange = Process Name '{0}' changed Priority from '{1}' to '{2}'. ProcessNotFound = Process Name '{0}' not found. Skip priority change. " } } process { foreach ($n in $Name) { try { # Get process $ps = Get-Process | where Name -eq $n # process exist check if ($null -ne $ps) { # what if check if ($PSBoundParameters.WhatIf.IsPresent) { $Host.UI.WriteLine(("What if: " + $message.PriorityChange -f $ps.Name, $ps.PriorityClass, $Priority)) } else { # process priority check if ($ps.PriorityClass -ne $Priority) { # execute Write-Verbose ($message.PriorityChange -f $ps.Name, $ps.PriorityClass, $Priority) $ps.PriorityClass = $Priority } else { # priority want to change was same as current. Write-Verbose ($message.PriorityNotChange -f $ps.Name, $ps.PriorityClass, $Priority) } } } else { # process missing Write-Warning ($message.ProcessNotFound -f $n) } } finally { # dispose item if ($ps -ne $null){$ps.Dispose()} } } } }
利用方法
いわゆる PowerShellファンクションとして利用可能です。 Name には、複数のプロセスをまとめて指定可能です。
パラメータ指定
パラメータを指定してもいいですね。 もちろん Priority は、インテリセンスに候補もでます。
Set-ProcessPriorityClass -Name "powershell" -Priority High -Verbose
VERBOSE: Process Name 'powershell' changed Priority from 'Normal' to 'High'.
パイプライン渡し
パイプラインからも渡せます。
Get-Process | where Name -eq PowerShell | Set-ProcessPriorityClass -Priority Normal -Verbose
VERBOSE: Process Name 'powershell' changed Priority from 'High' to 'Normal'.
スプラッティング渡し
いわゆる Splatting = HashTable に定義して渡す手法も可能です。
$param = @{ Name = "powershell" Priority = "High"} Set-ProcessPriorityClass @param -Verbose
VERBOSE: Process Name 'powershell' changed Priority from 'Normal' to 'High'.
WhatIf
-WhatIf
スイッチを付けることで、実行しないでどうなるかも事前に確認可能です。*3
Get-Process | where Name -eq PowerShell | Set-ProcessPriorityClass -Priority Normal -Verbose -WhatIf
What if: Process Name 'powershell' changed Priority from 'High' to 'Normal'.
まとめ
あとは、PSEvent でも while でもお好きなようにイベントを処理してください。
ふだん使うことは、まずないですね。