Probe Module: Top CPU Usage. (PowerShell)

Microsoft.Windows.Server.TopCPUUsage.ProbeAction.PowerShell (ProbeActionModuleType)

This probe action is used by CPU monitoring tasks and diagnostics in the version specific operating system management packs.

Element properties:

TypeProbeActionModuleType
IsolationAny
AccessibilityPublic
RunAsDefault
InputTypeSystem.BaseData
OutputTypeSystem.CommandOutput

Member Modules:

ID Module Type TypeId RunAs 
TopCPUUsageProbe ProbeAction System.CommandExecuterProbe Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
IntervalMillisecondsint$Config/IntervalMilliseconds$Interval (milliseconds)
NumSamplesint$Config/NumSamples$Num Samples

Source Code:

<ProbeActionModuleType ID="Microsoft.Windows.Server.TopCPUUsage.ProbeAction.PowerShell" Accessibility="Public">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="IntervalMilliseconds" type="xsd:int"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="NumSamples" type="xsd:int"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="IntervalMilliseconds" ParameterType="int" Selector="$Config/IntervalMilliseconds$"/>
<OverrideableParameter ID="NumSamples" ParameterType="int" Selector="$Config/NumSamples$"/>
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<ProbeAction ID="TopCPUUsageProbe" TypeID="System!System.CommandExecuterProbe">
<ApplicationName>%windir%\system32\windowspowershell\v1.0\powershell.exe</ApplicationName>
<WorkingDirectory/>
<CommandLine>-command "&amp; '$File/Microsoft.Windows.Server.TopCPUUsage.ps1$' $Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$ $Config/IntervalMilliseconds$ $Config/NumSamples$"</CommandLine>
<TimeoutSeconds>300</TimeoutSeconds>
<RequireOutput>true</RequireOutput>
<Files>
<File>
<Name>Microsoft.Windows.Server.TopCPUUsage.ps1</Name>
<Contents><Script>

param ([string] $TargetComputer, [Int] $SleepTime, [Int] $NumberOfSamples)

$ErrAction_None = 0
$ErrAction_Trace = 1
$ErrAction_ThrowError = 16
$ErrAction_Abort = 32
$ErrAction_ThrowErrorAndAbort = 48

$DISKSIZE_BYTES_IN_MB = 1048576

$g_ErrorEventNumber = 4001
$g_TraceEventNumber = 4002
$g_DebugFlag = $false

$WIN_SRV_2012_OSVer = "6.2"
#******************************************************************************
# FUNCTION: CheckByOSCurrentVersion
# DESCRIPTION: Returns True if the Registry Key for CurrentVersion
# is equal the target OS Versions Number.
# RETURNS: Boolean: True, if build is greater or equal than the given number
#******************************************************************************
function CheckByOSCurrentVersion()
{
$strCurrentOSVer = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\"
$strCurrentOSVer = $strCurrentOSVer.CurrentVersion
$CheckByOSCurrentVersion = $false
if($strCurrentOSVer -ge $WIN_SRV_2012_OSVer){
$CheckByOSCurrentVersion = $true
}else{
$CheckByOSCurrentVersion = $false
}
return $CheckByOSCurrentVersion;
}

$useCIM = CheckByOSCurrentVersion

#---------------------------------------------------------------------------
# Returns WMI Instance requested. Tries to execute WMI query a N times.
#---------------------------------------------------------------------------
Function WMIGetInstanceExTryN
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sInstanceQuery,
[int]$N)

for ($i = 0; $i -lt $N; $i++)
{
$error.Clear();
if($useCIM){
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oInstance = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
catch
{
$oInstance = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}else{
$oInstance = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
if ($error.Count -gt 0)
{
if ($i -eq ($N-1))
{
ThrowScriptError ("The class name '" + $sInstanceQuery + "' returned no instances. Please check to see if this is a valid WMI class name.") $error[0]
}
}
else
{
break;
}
sleep -m 1000
}

return $oInstance
}

#---------------------------------------------------------------------------
# Returns WMI Instance requested.
#---------------------------------------------------------------------------
Function WMIGetInstanceEx
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sInstanceQuery)

$error.Clear();
if($useCIM){

Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oInstance = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
catch
{
$oInstance = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}else{
$oInstance = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
if ($error.Count -gt 0)
{
ThrowScriptError ("The class name '" + $sInstanceQuery + "' returned no instances. Please check to see if this is a valid WMI class name.") $error[0]
}

return $oInstance
}

#---------------------------------------------------------------------------
# Connect to WMI.
#---------------------------------------------------------------------------
Function WMIConnect
{
param ([string]$sTargetComputer,
[string]$sNamespace, $sInstanceQuery)

$error.Clear()

# !!! Refactoring comment:
# Original VBScript only tries to connect to the namespace. Piping to get only the first one saves time.
if($useCIM)
{
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oWMI = Get-CimClass -CimSession $cimsession -Namespace $sNamespace -ErrorAction SilentlyContinue | select -First 1
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}else{
$oWMI = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue | select -First 1
}
if ($error.Count -gt 0)
{
$msg = "Unable to open WMI Namespace 'winmgmts:\\" + $sTargetComputer + "\" + $sNamespace + "'. Check to see if the WMI service is enabled and running, and ensure this WMI namespace exists."
ThrowScriptError $msg $error[0]
}
}

#---------------------------------------------------------------------------
# Returns WMI Instance requested.
#---------------------------------------------------------------------------
Function WMIGetInstance
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sInstanceQuery)

WMIConnect $sTargetComputer $sNamespace $sInstanceQuery
$oInstance = WMIGetInstanceEx $sTargetComputer $sNamespace $sInstanceQuery
return $oInstance
}

#---------------------------------------------------------------------------
# Returns WMI Instance requested.
#---------------------------------------------------------------------------
Function WMIGetInstanceNoAbort
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sInstanceQuery)
if($useCIM){
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oInstance = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
catch
{
$oInstance = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}else{
$oInstance = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
return $oInstance
}

#---------------------------------------------------------------------------
# Executes the WMI query and returns the result set.
#---------------------------------------------------------------------------
Function WMIExecQuery
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sQuery)

$error.Clear()

if($useCIM){

Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oQuery = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}
catch
{
$oQuery = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}else{
$oQuery = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}
if ($error.Count -gt 0)
{
ThrowScriptError ("The Query '" + $sQuery + "' returned an invalid result set. Please check to see if this is a valid WMI Query.") $error[0]
}

return $oQuery
}

#---------------------------------------------------------------------------
# Executes the WMI query and returns the result set, no abort version.
#---------------------------------------------------------------------------
Function WMIExecQueryNoAbort
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sQuery)
if($useCIM){
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oQuery = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}
catch
{
$oQuery = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}else{
$oQuery = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}

return $oQuery
}

#---------------------------------------------------------------------------
# Creates an event and sends it back to the mom server.
#---------------------------------------------------------------------------
Function ThrowScriptErrorNoAbort
{
param ([string]$sMessage,
[System.Management.Automation.ErrorRecord]$oErr)
# Retrieve the name of this (running) script
$ScriptFileName = $MyInvocation.ScriptName

if ($oErr -ne $null)
{
$sMessage = $sMessage + ". " + $oErr.ErrorDetails
}

$momAPI.LogScriptEvent($ScriptFileName, $g_ErrorEventNumber, $EVENT_TYPE_ERROR, $sMessage)

Write-Host $sMessage
}

#---------------------------------------------------------------------------
# Creates an event and sends it back to the mom server.
#---------------------------------------------------------------------------
Function ThrowScriptError
{
param ([string]$sMessage,
[System.Management.Automation.ErrorRecord]$oErr)
ThrowScriptErrorNoAbort $sMessage $oErr
exit
}

#---------------------------------------------------------------------------
# Outputs to file and echo for debugging purposes
#---------------------------------------------------------------------------
Function TraceLogMessage
{
param ([string]$sMessage)

Write-Host $sMessage

If ($g_DebugFlag -eq $true)
{
# Retrieve the name of this (running) script
$ScriptFileName = $MyInvocation.ScriptName

$momAPI.LogScriptEvent($ScriptFileName, $g_TraceEventNumber, $EVENT_TYPE_INFORMATION, $sMessage)
}
}

#---------------------------------------------------------------------------
# Verifies the expression. If equals to False then generates an error and quits the script
# Usage:
# Verify Not WMISet Is Nothing, "WMISet is invalid!"
# Verify WMISet.Count = 1, "Invalid quantity of services with name 'Server' (qty = " &amp; WMISet.Count &amp; ")."
#---------------------------------------------------------------------------
Function Verify
{
param ([bool]$bBool,
[string]$sMessage)

If ($bBool -eq $false)
{
ThrowScriptError $sMessage $null
}
}

Function GetRegistryKeyValue
{
param ([string]$keyPath,
[string]$key)

$error.Clear()

$strKeyValue = Get-ItemProperty -Path $keyPath -Name $key -ErrorAction SilentlyContinue
if ($error.Count -gt 0)
{
ThrowScriptError ("An error occurred while reading the registry: '" + $keyPath + $key + "'") $error[0]
}
return $strKeyValue.$key
}


#---------------------------------------------------------------------------
# Function: ExpressedInMB
# Usage:
# Parameter (SizeInBytes)
# Returns the Size Expressed in MBytes
#---------------------------------------------------------------------------
Function ExpressedInMB
{
param ($SizeInBytes)

$NumberSizeExpInMB = [math]::Round($SizeInBytes / $DISKSIZE_BYTES_IN_MB, 0)
return $NumberSizeExpInMB
}

Function Load-CimModules
{
$error.Clear()

$CimModule = Get-Module CimCmdlets

if ($null -eq $CimModule)
{
Import-Module CimCmdlets
$error.Clear()
}
}#Copyright (c) Microsoft Corporation. All rights reserved.

# Parameters that should be passed to this script
# 0 Computer (FQDN)
# 1 SleepTime - interval (in milliseconds) between samples
# 2 NumberOfSamples

Function Main()
{
$lNumProcessors = GetNumProcessors $TargetComputer

# List processes using more than 1% of processor time (take into account the number of CPU).
# Sample &lt;NumberOfSamples&gt; times waiting &lt;SleepTime&gt; milliseconds between samples.

$processDictionary = @{}
for ($i = 1; $i -le $NumberOfSamples; $i++)
{
sleep -m $SleepTime

$PerfProc_Process = WMIGetInstanceEx $TargetComputer "root\cimv2" "Win32_PerfFormattedData_PerfProc_Process"

foreach ($process in $PerfProc_Process)
{
if ($process.Name -ne "_Total" -and $process.Name -ne "Idle") #-and $process.PercentProcessorTime -gt $lNumProcessors)
{
$key = $process.Name + "::" + $process.IDProcess
if ($processDictionary.ContainsKey($key))
{
$processDictionary[$key] = [double]$processDictionary[$key] + [double]$process.PercentProcessorTime
}
else
{
$processDictionary[$key] = [double]$process.PercentProcessorTime
}
}
}
}


# Collected Samples

# Get the keys
foreach ($key in $($processDictionary.Keys))
{
$processDictionary[$key] = [double]$processDictionary[$key] / [double]$NumberOfSamples / [double]$lNumProcessors
}

# Sort the array
$sortedProcessDictionary = $processDictionary.GetEnumerator() | Sort-Object -Property Value -Descending

Write-Host "% CPU Time(Avg) PID Binary Name "
Write-Host "==============================================================================="

for ($i = 0; $i -lt $sortedProcessDictionary.Count; $i++)
{
if ($sortedProcessDictionary[$i].Value -le 0)
{
break
}
$pValue = ([math]::Truncate($sortedProcessDictionary[$i].Value*10) / 10).ToString()
$pName = ($sortedProcessDictionary[$i].Key -split "::")[0]
$processid = ($sortedProcessDictionary[$i].Key -split "::")[1]
$OutPutString = " " + $pValue + "%"
for ($j = 0; $j -le (5-$pValue.Length); $j++) { $OutPutString += " " }
$OutPutString += " " + $processid
for ($j = 0; $j -le (8-$processid.Length); $j++) { $OutPutString += " " }
$OutPutString += " " + $pName
Write-Host $OutPutString
}
}

# Windows Server 2003, Windows XP, and Windows 2000: Because the NumberOfLogicalProcessors property
# is not available, NumberOfProcessors indicates the number of logical processors available in the
# system. In the case of a computer system that has two physical processors each containing two
# logical processors, the value of NumberOfProcessors is 4.
# For more information see "http://msdn2.microsoft.com/en-us/library/aa394102(VS.85).aspx"
Function GetNumProcessors{
param ([string]$sTargetComputer)

$WMISet = WMIGetInstanceEx $sTargetComputer "root\cimv2" "Win32_ComputerSystem"
foreach ($owObj in $WMISet)
{
$error.Clear()
$NumProcessors = $owObj.NumberOfLogicalProcessors
if ($error.Count -ne 0)
{
$NumProcessors = $owObj.NumberOfProcessors
}
return $NumProcessors
}
}

Main
</Script></Contents>
</File>
</Files>
</ProbeAction>
</MemberModules>
<Composition>
<Node ID="TopCPUUsageProbe"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.CommandOutput</OutputType>
<InputType>System!System.BaseData</InputType>
</ProbeActionModuleType>