如果进程达到CPU使用率的x%,则终止进程

时间:2017-04-12 19:54:44

标签: powershell

我想停止运行CPU使用率超过14%的进程。

$process = get-process
    foreach ($proc in (Get-WmiObject  Win32_Processor)){
if($proc.numberofcores -eq $null){
    $cores++
}else{
    $cores = $cores + $proc.numberofcores
}
} 
foreach($name in $process){
    $processName = $name.processName
foreach($hog in $processName){
       $cpuusage = [Math]::round(((((Get-Counter "\Process($processName)\% 
Processor Time" -MaxSamples 2).Countersamples)[0].CookedValue)/$cores),2)

        if($cpuusage -gt 14){
            Stop-Process -Name $processName
        }
}
}

我将以下内容视为错误,没有别的。我希望Idle(0)不起作用,但没有其他任何东西被杀死。

  

停止处理:由于以下原因,无法停止处理“空闲(0)”       错误:访问被拒绝       在行:14 char:17       + Stop-Process -Name $ processName       + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~       + CategoryInfo:CloseError:(System.Diagnostics.Process       (空闲):进程)[Stop-Process],ProcessCommandException       + FullyQualifiedErrorId:        CouldNotStopProcess,Microsoft.PowerShell.Commands.StopProcessCommand

我尝试将第二个foreach循环中的$processName变量替换为$hog,但仍然会出现相同的错误。

在阅读@JosefZ答案后,我得到了满足我课堂要求的东西。在此发布以供参考;

$process = get-process
foreach ($pro in $process){
    $name = $pro.ProcessName
    $CpuCores = (Get-WmiObject -Class Win32_Processor).NumberOfCores
    $CpuValue = ((Get-Counter "\Process($name)\% Processor Time").CounterSamples.CookedValue)/$CpuCores
    $percent = [Decimal]::Round($CpuValue, 3)
        if($percent -ge 15){
        Stop-Process -Name $name
        $wshell = New-Object -ComObject Wscript.Shell
        $wshell.Popup("Process $name was using more than $percent % CPU. We have eliminated it.",0,"Ok",0x1)
    }
}

2 个答案:

答案 0 :(得分:3)

请注意Performance counters are often protected by access control lists (ACLs). To get all available performance counters, open Windows PowerShell with the "Run as administrator" optionYour ability to stop processes depends on your permissions.

以下脚本用于调试CPU耗时wmic path cim_datafile和防病毒全扫描:

Set-StrictMode -Version latest
$process = get-process
$cores = 0
foreach ($proc in (Get-WmiObject  Win32_Processor)){
    if($proc.numberofcores -eq $null){
        $cores++
    }else{
        $cores = $cores + $proc.numberofcores
    }
} 
### $cores
foreach($name in $process){
    $processName = $name.processName
    if ( $processName -notmatch "^Idle" ) {
        foreach($hog in $processName){
            $cpuusage = -1
            $cpuusage = [Math]::round(((((Get-Counter "\Process($processName)\% Processor Time" -MaxSamples 2).Countersamples)[0].CookedValue)/$cores),2)
            if ($cpuusage -gt 14) {
                Stop-Process -Name $processName -PassThru -ErrorAction Continue
                ### "{0} {1} {2} {3}" -f '+', $cpuusage, $name.Id, $processName
            } else {
                if($cpuusage -ne 0){
                    ### "{0} {1} {2} {3}" -f '-', $cpuusage, $name.Id, $processName
                }
            }
        }
    }
}

肮脏的解决方案Stop-Process -Name $processName -ErrorAction SilentlyContinue -PassThru

"Idle"表示“无效”(未运行或正在使用)。当“系统空闲进程”位于100 %时,这意味着没有任何东西在使用您的CPU资源。

在MSDN上阅读Stopping Processes (Stop-Process)

  

Windows PowerShell为您提供了列出流程的灵活性,但是   怎么停止一个过程?

     

Stop-Process cmdlet需要NameId来指定进程   你想停下来你停止流程的能力取决于你的   权限。 某些流程无法停止。例如,如果你   尝试停止空闲进程,出现错误:

PS> Stop-Process -Name Idle
Stop-Process : Process 'Idle (0)' cannot be stopped due to the following error:
 Access is denied
At line:1 char:13
+ Stop-Process  <<<< -Name Idle

阅读Get-Help 'Stop-Process' -Online

  

<强>输出

     

System.Diagnostics.Process

     

此cmdlet返回表示已停止进程的System.Diagnostics.Process对象,如果指定PassThru,则返回   参数即可。否则,此cmdlet不会生成任何输出。

答案 1 :(得分:1)

为您提供了一些额外的指示。首先,您应使用Win32_ComputerSystemNumberOfLogicalProcessors代替Win32_Processor NumberOfCores。原因是,性能计数器在具有它的系统上占用HyperThreading,因此基于物理内核的计算将为您提供两倍于其应有的处理器时间值。例如,在我的具有6个物理内核的机器上,由于超线程,我有12个逻辑处理器。使用原始计算,使用8%CPU的进程将报告为16%,因此会被错误地停止。 Win32_ComputerSystem版本将返回所有物理CPU的所有逻辑处理器,因此也可以正确计算多个插槽服务器。

C:\WINDOWS\system32> (Get-WmiObject win32_processor).NumberofCores
6
C:\WINDOWS\system32> (Get-WmiObject win32_computersystem).Numberoflogicalprocessors
12

其次,你应该通过它的ID而不是名字来停止这个过程,因为这会产生意想不到的后果。一个简单的例子是Chrome,每个标签都有一个进程,所有这些都有名称Chrome。因此,单个选项卡可能会导致导致CPU过高的问题,但是调用Stop-Process -Name Chrome的脚本会关闭所有Chrome实例,包括那些无法执行任何操作的实例。

以下示例脚本解决了这两个问题:

#Get all cores, which includes virtual cores from hyperthreading
$cores = (Get-WmiObject  Win32_ComputerSystem).NumberOfLogicalProcessors
#Get all process with there ID's, excluding processes you can't stop.
$processes = ((Get-Counter "\Process(*)\ID Process").CounterSamples).where({$_.InstanceName -notin "idle","_total","system"})
#Get cpu time for all processes
$cputime = $processes.Path.Replace("id process", "% Processor Time") | get-counter | select -ExpandProperty CounterSamples
#Get the processes with above 14% utilisation.
$highUsage = $cputime.where({[Math]::round($_.CookedValue / $cores,2) -gt 14})
# For each high usage process, grab it's process ID from the processes list, by matching on the relevant part of the path
$highUsage |%{
    $path = $_.Path
    $id = $processes.where({$_.Path -like "*$($path.Split('(')[1].Split(')')[0])*"}) | select -ExpandProperty CookedValue
    Stop-Process -Id $id -Force -ErrorAction SilentlyContinue
}

请注意,.where(语法的使用需要PowerShell 5或更高版本。这个脚本还有额外的好处,比在foreach循环中调用Get-Counter要快得多。