Agent processor utilization calculator script

Microsoft.SystemCenter.HealthService.SCOMpercentageCPUTimeScriptProbe (ProbeActionModuleType)

agent processor utilization calculator script

Knowledge Base article:

Summary

Agent processor utilization calculator script.

Element properties:

TypeProbeActionModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
InputTypeSystem.BaseData
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
Probe ProbeAction Microsoft.Windows.PowerShellPropertyBagProbe Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
TimeoutSecondsint$Config/TimeoutSeconds$Timeout (seconds)
ProcessIterationCountint$Config/ProcessIterationCount$Number of samples

Source Code:

<ProbeActionModuleType ID="Microsoft.SystemCenter.HealthService.SCOMpercentageCPUTimeScriptProbe" Accessibility="Internal" Batching="false" PassThrough="false">
<Configuration>
<xsd:element minOccurs="1" name="TimeoutSeconds" type="xsd:integer"/>
<xsd:element minOccurs="1" name="ComputerName" type="xsd:string"/>
<xsd:element minOccurs="1" name="RunAsDiagnostic" type="xsd:boolean"/>
<xsd:element minOccurs="1" name="ProcessIterationCount" type="xsd:integer"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
<OverrideableParameter ID="ProcessIterationCount" Selector="$Config/ProcessIterationCount$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<ProbeAction ID="Probe" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagProbe">
<ScriptName>SCOMpercentageCPUTimeCounter.ps1</ScriptName>
<ScriptBody><Script>
Param([string]$ComputerName, [string]$ConfigForRun, [int]$ProcessIterationCount)
#Process Arguments:
# 0 - ComputerIdentity
# 1 - RunAsDiagnostic
# 2 - ProcessIterationCount

#Event log variables
$SCRIPT_EVENT_ID = 3000
$CN_SCOM_SUCCESS = 0
$CN_SCOM_ERROR = 1
$CN_SCOM_WARNING = 2
$CN_SCOM_INFORMATION = 4
$SCRIPT_NAME = "SCOMPercentageCPUTimeCounter.ps1"

#OS version for Win 2012
$WIN_OS_2012_Ver = "6.2"
$OSRegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\"

#******************************************************************************
# FUNCTION: CheckMinOSVer
# DESCRIPTION: Returns True if the Registry Key for CurrentVersion
# is equal or Higher than the Minimum OS Versions Number.
# PARAMETER: DblMinVer Minimum Version Number to use
# RETURNS: Boolean: True, if build is greater or equal than the given number
#******************************************************************************
function CheckByOSCurrentVersion() #As Boolean
{
$strCurrentOSVer = Get-ItemProperty $OSRegistryKey
$strCurrentOSVer = $strCurrentOSVer.CurrentVersion
if($strCurrentOSVer -ge $WIN_OS_2012_Ver)
{
return $true;
}
return $false;
}

Function Load-CimModules
{
$error.Clear()

$CimModule = Get-Module CimCmdlets

if ($null -eq $CimModule)
{
Import-Module CimCmdlets
$error.Clear()
}
}



function GetProcessorTime ($procId, $ComputerName)
{

$N1 = 0
$D1 = 0
$N2 = 0
$D2 = 0
$Nd = 0
$Dd = 0
$PercentProcessorTime = 0
$query = "Select * from Win32_PerfRawData_PerfProc_Process where IDProcess = ""$procId"""
if($isHigherThanWin08 -eq $true)
{
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $ComputerName -SessionOption $cimSessionOption
$objService1 = Get-CimInstance -CimSession $cimsession -Namespace "root\cimv2" -Query $query -ErrorAction Stop
}
catch
{
$objService1 = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Query $query -ErrorAction Stop
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}

}
else
{
$objService1 = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Query $query
}
ForEach($objInstance1 in $objService1)
{
$N1 = $objInstance1.PercentProcessorTime
$D1 = $objInstance1.TimeStamp_Sys100NS
}

Start-Sleep 1
if($isHigherThanWin08 -eq $true)
{
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $ComputerName -SessionOption $cimSessionOption
$objService2 = Get-CimInstance -CimSession $cimsession -Namespace "root\cimv2" -Query $query -ErrorAction Stop
}
catch
{
$objService2 = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Query $query -ErrorAction Stop
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}
else
{
$objService2 = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Query $query
}
ForEach($objInstance2 in $objService2)
{
$N2 = $objInstance2.PercentProcessorTime
$D2 = $objInstance2.TimeStamp_Sys100NS
}

$Nd = $N2-$N1
$Dd = $D2-$D1
$PercentProcessorTime = $($($Nd/$Dd) * 100)
return $PercentProcessorTime

}

#Check the OS version
$isHigherThanWin08 = CheckByOSCurrentVersion

#Create PropertyBag object
$oAPI = new-object -comObject "MOM.ScriptAPI"
$oPropertyBag = $oAPI.CreatePropertyBag()

#Set the retry attempts for WMI and other counters
$retryAttempts = 2
$dataCount = 0

#Get WMI object
$finalPercentProcessorTime = 0
$procCount = 0
$checker = $null
if($isHigherThanWin08 -eq $true)
{
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $ComputerName -SessionOption $cimSessionOption
$checker = Get-CimInstance -CimSession $cimsession -Namespace "root\cimv2" -Class "Win32_Process" -ErrorAction Stop
}
catch
{
$checker = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Class "Win32_Process" -ErrorAction Stop
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}
else
{
$checker = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Class "Win32_Process"
}

if($checker -ne $null)
{
for($counter=0;$counter -lt $retryAttempts;$counter++)
{
# Get the number of cores in the system
if($isHigherThanWin08 -eq $true)
{
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $ComputerName -SessionOption $cimSessionOption
$processorList = Get-CimInstance -CimSession $cimsession -Namespace "root\cimv2" -Query "SELECT NumberOfCores FROM Win32_Processor" -ErrorAction Stop
}
catch
{
$processorList = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Query "SELECT NumberOfCores FROM Win32_Processor" -ErrorAction stop
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}
else
{
$processorList = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Query "SELECT NumberOfCores FROM Win32_Processor" -ErrorAction stop
}
if($processorList -ne $null)
{
foreach($processor in $processorList)
{
$procCount = $procCount + $processor.NumberOfCores
}
break
}
}
if($procCount -lt 1)
{
$procCount = 1
}

#Set the variables for detailed analysis
$min = 32767
$max = 0
$sampleCount = 0
$totalCount = 0
$procTime = 0

#Process id of current script is $pid

# Get the total processor time count ProcessIterationCount number of times, to get the average
for($loopCounter=0; $loopCounter -lt $ProcessIterationCount; $loopCounter++)
{
$agentProcIDs = "|"
# Step 1: Get all SCOM Processes
for($counter=0; $counter -lt $retryAttempts; $counter++)
{
if($isHigherThanWin08 -eq $true)
{
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $ComputerName -SessionOption $cimSessionOption
$processes = Get-CimInstance -CimSession $cimsession -Namespace "root\cimv2" -Query "SELECT ProcessId, ParentProcessId, Name FROM Win32_Process" -ErrorAction Stop
}
catch
{
$processes = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Query "SELECT ProcessId, ParentProcessId, Name FROM Win32_Process" -ErrorAction stop
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}
else
{
$processes = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Query "SELECT ProcessId, ParentProcessId, Name FROM Win32_Process" -ErrorAction stop
}
if($processes -ne $null)
{
# Step 2: Get the Health Service and Monitoring Host objects
foreach($process in $processes)
{
if(($process -ne $null) -and ($process.GetType().Name -ne "Nothing"))
{
if(($process.Name.contains("HealthService") -Or $process.Name.contains("MonitoringHost")) -And (-Not($agentProcIDs.contains($("|" + $process.ProcessId + "|")))))
{
$agentProcIDs = $($agentProcIDs + $process.ProcessId + "|")
}
}
}

# Step 3: Get all the child processes
$childFound = $true
# While a new child is found, re-iterate the list to find its child
DO
{
$childFound = $false
foreach($process in $processes)
{
if(($process -ne $null) -and ($process.GetType().Name -ne "Nothing"))
{
# If parent process is in the agentProcIDs list but the process itself is not, its a new child

# Filter out myself
if($process.ProcessId -ne $pid)
{
if($agentProcIDs.contains($("|" + $process.ParentProcessId + "|")) -And (-Not($agentProcIDs.contains($("|" + $process.ProcessId + "|")))))
{
$agentProcIDs = $($agentProcIDs + $process.ProcessId + "|")
$childFound = $true
}
}
}
}
}While($childFound -eq $true)

# Step 4: Get the total cpu percentage used for all the SCOM processes
if($isHigherThanWin08 -eq $true)
{
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $ComputerName -SessionOption $cimSessionOption
$wmiService = Get-CimInstance -CimSession $cimsession -Namespace "root\cimv2" -Class Win32_PerfFormattedData_PerfProc_Process -ErrorAction Stop
}
catch
{
$wmiService = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Class Win32_PerfFormattedData_PerfProc_Process -ErrorAction stop
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}
else
{
$wmiService = Get-WMIObject -Namespace "root\cimv2" -ComputerName $ComputerName -Class Win32_PerfFormattedData_PerfProc_Process
}
$totalPercentProcessorTime = 0


# Iterate each process to add the percent processor time to the to
foreach($process in $wmiService)
{
if($agentProcIDs.Contains($("|" + $process.IDProcess + "|")))
{
$x = $(GetProcessorTime $process.IDProcess $ComputerName)
$totalPercentProcessorTime = $totalPercentProcessorTime + $x
if($ConfigForRun -eq $true)
{
$procTime = $x
$sampleCount = $sampleCount + 1
$procTime = [double]$procTime
$totalCount = $totalCount + $procTime

# Check for min value
if($procTime -lt $min)
{
$min = $procTime
}
# Check for max value
if($procTime -gt $max)
{
$max = $procTime
}
}
}
}

# Add the total percentage time to the final percentage time for averaging in the end
$finalPercentProcessorTime = $finalPercentProcessorTime + $totalPercentProcessorTime
$dataCount = $dataCount + 1
break
}
}

# Delaying each iteration by 3 seconds
Start-Sleep 3
}
# Add the detailed analysis to the property bag
if($ConfigForRun -eq $true)
{
$oPropertyBag.AddValue("SamplesTaken", $ProcessIterationCount)
$oPropertyBag.AddValue("Average", [double]($totalCount/$sampleCount))
$oPropertyBag.AddValue("Maximum", $max)
$oPropertyBag.AddValue("Minimum", $min)
}
# Calculate the final percentage processor time for all the SCOM processes
if($dataCount -lt 1)
{
$dataCount = 1
}
$finalPercentProcessorTime = ($finalPercentProcessorTime/$dataCount)/$procCount
}
else
{
$message = $("Can't initialize the com object")
$oAPI.LogScriptEvent($SCRIPT_NAME, $SCRIPT_EVENT_ID, $CN_SCOM_ERROR, $message)
}
if($ConfigForRun -eq $false)
{
$oPropertyBag.AddValue("SCOMpercentageCPUTime", $finalPercentProcessorTime)
}
$oPropertyBag

</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>ComputerName</Name>
<Value>$Config/ComputerName$</Value>
</Parameter>
<Parameter>
<Name>ConfigForRun</Name>
<Value>$Config/RunAsDiagnostic$</Value>
</Parameter>
<Parameter>
<Name>ProcessIterationCount</Name>
<Value>$Config/ProcessIterationCount$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</ProbeAction>
</MemberModules>
<Composition>
<Node ID="Probe"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
<InputType>System!System.BaseData</InputType>
</ProbeActionModuleType>