# encoding: ascii
# api: powershell
# title: Get-TopProcess
# description: Returns the top processes by CPU usage
# version: 0.1
# type: function
# author: BSonPosh
# license: CC0
# function: get-diskActivity
# x-poshcode-id: 1225
# x-archived: 2012-12-31T14:12:47
# x-published: 2009-07-23T07:29:00
#
#
param(
[string] $sortCriteria = "Processor",
[int] $Count = 5
)
function main
{
## Store the performance counters we need
## for the CPU, and Disk I/O numbers
$cpuPerfCounters = @{}
$ioOtherOpsPerfCounters = @{}
$ioOtherBytesPerfCounters = @{}
$ioDataOpsPerfCounters = @{}
$ioDataBytesPerfCounters = @{}
$processes = $null
$lastPoll = get-date
$lastSnapshotCount = 0
$lastWindowHeight = 0
$processes = get-process | sort Id
## Go through all of the processes we captured
foreach($process in $processes)
{
## Get the disk activity, based on I/O Perf Counters,
## for the process in question. Then, add it as a note.
$cpuPercent = @(for($i=0;$i -lt 10;$i++)
{
get-cpuPercent $process
}) | measure-object -average
[int]$Percent = $cpuPercent.Average
#$process | add-member NoteProperty Disk $activity -force
$process | add-member NoteProperty Processor $Percent -force
}
$output = $processes | sort -desc $sortCriteria | select -first $Count
$output | format-table Id,ProcessName,MainWindowTitle,WorkingSet
}
## As a heuristic, gets the total IO and Data operations per second, and
## returns their sum.
function get-diskActivity (
$process = $(throw "Please specify a process for which to get disk usage.")
)
{
$processName = get-processName $process
## We store the performance counter objects in a hashtable. If we don't,
## then they fail to return any information for a few seconds.
if(-not $ioOtherOpsPerfCounters[$processName])
{
$ioOtherOpsPerfCounters[$processName] = new-object System.Diagnostics.PerformanceCounter("Process","IO Other Operations/sec",$processName)
}
if(-not $ioOtherBytesPerfCounters[$processName])
{
$ioOtherBytesPerfCounters[$processName] = new-object System.Diagnostics.PerformanceCounter("Process","IO Other Bytes/sec",$processName)
}
if(-not $ioDataOpsPerfCounters[$processName])
{
$ioDataOpsPerfCounters[$processName] = new-object System.Diagnostics.PerformanceCounter("Process","IO Data Operations/sec",$processName)
}
if(-not $ioDataBytesPerfCounters[$processName])
{
$ioDataBytesPerfCounters[$processName] = new-object System.Diagnostics.PerformanceCounter("Process","IO Data Bytes/sec",$processName)
}
## If a process exits between the time we capture the processes and now,
## then we will be unable to get its NextValue(). This trap simply
## catches the error and continues.
trap { continue; }
## Get the performance counter values
$ioOther = (100 * $ioOtherOpsPerfCounters[$processName].NextValue()) + ($ioOtherBytesPerfCounters[$processName].NextValue())
$ioData = (100 * $ioDataOpsPerfCounters[$processName].NextValue()) + ($ioDataBytesPerfCounters[$processName].NextValue())
return [int] ($ioOther + $ioData)
}
## Get the percentage of time spent by a process.
## Note: this is multiproc "unaware." We need to divide the
## result by the number of processors.
function get-cpuPercent (
$process = $(throw "Please specify a process for which to get CPU usage.")
)
{
$processName = get-processName $process
## We store the performance counter objects in a hashtable. If we don't,
## then they fail to return any information for a few seconds.
if(-not $cpuPerfCounters[$processName])
{
$cpuPerfCounters[$processName] = new-object System.Diagnostics.PerformanceCounter("Process","% Processor Time",$processName)
}
## If a process exits between the time we capture the processes and now,
## then we will be unable to get its NextValue(). This trap simply
## catches the error and continues.
trap { continue; }
## Get the performance counter values
$cpuTime = ($cpuPerfCounters[$processName].NextValue() / $env:NUMBER_OF_PROCESSORS)
return [int] $cpuTime
}
## Performance counters are keyed by process name. However,
## processes may share the same name, so duplicates are named
## <process>#1, <process>#2, etc.
function get-processName (
$process = $(throw "Please specify a process for which to get the name.")
)
{
## If a process exits between the time we capture the processes and now,
## then we will be unable to get its information. This simply
## ignores the error.
$errorActionPreference = "SilentlyContinue"
$processName = $process.ProcessName
$localProcesses = get-process -ProcessName $processName | sort Id
if(@($localProcesses).Count -gt 1)
{
## Determine where this one sits in the list
$processNumber = -1
for($counter = 0; $counter -lt $localProcesses.Count; $counter++)
{
if($localProcesses[$counter].Id -eq $process.Id) { break }
}
## Append its unique identifier, if required
$processName += "#$counter"
}
return $processName
}
. main