Have a complaint from a user that a server is sluggish? Maybe you’re just curious if the problem you’re seeing on a server is related to a process consuming a lot of CPU, or you know the CPU is pegged and you want to identify which process is the culprit.

I had a similar situation, and so I wrapped it up into a nice little package that I’ll share with you here. This uses WMI to find processes running high CPU with PowerShell.

It can run in one of two ways – by reporting all processes using more than a certain percentage of the CPU or by reporting a the top CPU hogging processes. I use parameter sets for those different options, so it’s one or the other. I considered making it possible to list “top 3 processes consuming more than 10%,” which could have been done very easily, but decided I preferred it this way.

Function Get-iLPHighCPUProcess {
<#
.SYNOPSIS
    Retrieve processes that are utilizing the CPU on local or remote systems.

.DESCRIPTION
    Uses WMI to retrieve process information from remote or local machines. You can specify to return X number of the top CPU consuming processes
    or to return all processes using more than a certain percentage of the CPU.

.EXAMPLE
    Get-HighCPUProcess

    Returns the 3 highest CPU consuming processes on the local system.

.EXAMPLE
    Get-HighCPUProcess -Count 1 -Computername AppServer01

    Returns the 1 highest CPU consuming processes on the remote system AppServer01.


.EXAMPLE
    Get-HighCPUProcess -MinPercent 15 -Computername "WebServer15","WebServer16"

    Returns all processes that are consuming more that 15% of the CPU process on the hosts webserver15 and webserver160
#>

[Cmdletbinding(DefaultParameterSetName="ByCount")]
Param(
    [Parameter(ValueFromPipelineByPropertyName)]
    [Alias("PSComputername")]
    [string[]]$Computername = "localhost",
    
    [Parameter(ParameterSetName="ByPercent")]
    [ValidateRange(1,100)]
    [int]$MinPercent,

    [Parameter(ParameterSetName="ByCount")]
    [int]$Count = 3
)


Process {
    Foreach ($computer in $Computername){
    
        Write-Verbose "Retrieving processes from $computer"
        $wmiProcs = Get-WmiObject Win32_PerfFormattedData_PerfProc_Process -Filter "idProcess != 0" -ComputerName $Computername
    
        if ($PSCmdlet.ParameterSetName -eq "ByCount") {
            $wmiObjects = $wmiProcs | Sort PercentProcessorTime -Descending | Select -First $Count
        } elseif ($psCmdlet.ParameterSetName -eq "ByPercent") {
            $wmiObjects = $wmiProcs | Where {$_.PercentProcessorTime -ge $MinPercent} 
        } #end IF

        $wmiObjects | Foreach {
            $outObject = [PSCustomObject]@{
                Computername = $computer
                ProcessName = $_.name
                Percent = $_.PercentProcessorTime
                ID = $_.idProcess
            }
            $outObject
        } #End ForeachObject
    } #End ForeachComputer
}

}

Things I like about this function are:

  • Concise output: Computername, ProcessName, Percent (of CPU), and ID (Process ID)
  • Accepts pipeline input by property value of “ComputerName” or “PSComputerName”
  • Easy to use against multiple computers
  • Flexible: I like the option to find the 3 highest CPU processes or all processes above 5 percent (or any percent)
  • Accepts multiple computers through parameter (as an array) or through the pipeline

Questions? Comments? Whether it’s a different approach or just saying “Thanks” I really appreciate the feedback.