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.ScriptPropertyBagProbe 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.ScriptPropertyBagProbe">
<ScriptName>SCOMpercentageCPUTimeCounter.vbs</ScriptName>
<Arguments>$Config/ComputerName$ $Config/RunAsDiagnostic$ $Config/ProcessIterationCount$</Arguments>
<ScriptBody><Script>
'Copyright (c) Microsoft Corporation. All rights reserved.

Option Explicit

Call Main

Function GetProcessorTime(ProcID, objService)
Dim N1, D1, N2, D2, Nd, Dd, PercentProcessorTime
Dim objInstance1, objInstance2
On Error Resume Next

For Each objInstance1 in objService.ExecQuery("Select * from Win32_PerfRawData_PerfProc_Process where IDProcess = '" &amp; ProcID &amp; "'")
N1 = objInstance1.PercentProcessorTime
D1 = objInstance1.TimeStamp_Sys100NS
Exit For
Next

WScript.Sleep(1000)

For Each objInstance2 in objService.ExecQuery("Select * from Win32_PerfRawData_PerfProc_Process where IDProcess = '" &amp; ProcID &amp; "'")
N2 = objInstance2.PercentProcessorTime
D2 = objInstance2.TimeStamp_Sys100NS
Exit For
Next

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

if Err.Number &lt;&gt; 0 Then
GetProcessorTime = 0
else
GetProcessorTime = Round(PercentProcessorTime ,3)
end if
End Function

Sub Main
' Setup initial configuration
SetLocale("en-us")
InitializeCommon(1000)
Dim errorNum
errorNum = 0

' Check Arguments
Dim oArgs
Set oArgs = WScript.Arguments
If oArgs.Count &lt; 3 Then
ThrowScriptError "Invalid parameters passed to " &amp; GetScriptName &amp; ".", Null
End If

' Process Arguments:
' 0 - ComputerIdentity
' 1 - RunAsDiagnostic
' 2 - ProcessIterationCount
Dim ComputerIdentity, RunAsDiagnostic, ProcessIterationCount
ComputerIdentity = oArgs(0)
RunAsDiagnostic = CBool(oArgs(1))
ProcessIterationCount = CInt(oArgs(2))

' Create PropertyBag object
Dim oAPI, oPropertyBag
Set oAPI = MOMCreateObject("MOM.ScriptAPI")
Set oPropertyBag = oAPI.CreatePropertyBag()

' Set the retry attempts for Wmi and other counters
Dim loopCounter, counter, retryAttempts, dataCount
retryAttempts = 3
dataCount = 0

' Get WMI object
Dim oWMIService, finalPercentProcessorTime
finalPercentProcessorTime = 0

On Error Resume Next
Set oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &amp; ComputerIdentity &amp; "\root\cimv2")
errorNum = Err.Number
On Error Goto 0
If (errorNum = 0) Then

' Get the number of cores in the system
Dim oProcessor, oProcessorList, procCount
procCount = 0
On Error Resume Next
For counter = 1 to retryAttempts
Set oProcessorList = oWMIService.ExecQuery("SELECT NumberOfCores FROM Win32_Processor")
If (IsListEmpty(oProcessorList) = False) Then
Exit For
End If
Next
If (IsListEmpty(oProcessorList) = False) Then
For Each oProcessor in oProcessorList
procCount = procCount + oProcessor.NumberOfCores
Next
End If
On Error Goto 0
If procCount &lt; 1 Then
procCount = 1
End If

' Set the variables for detailed analysis
Dim min, max, sampleCount, totalCount, procTime
min = 32767
max = 0
sampleCount = 0
totalCount = 0
procTime = 0

'Find process id of current script
Dim processes, process, myProcessId
Set processes = oWMIService.execQuery("select ProcessID, Caption, CommandLine from win32_process")
For Each process In processes
with process
If .caption="cscript.exe" and InStr(.CommandLine, WScript.ScriptName) &gt; 0 Then
myProcessId = .ProcessID
end if
End with
Next


' Get the total processor time count ProcessIterationCount number of times, to get the average
For loopCounter = 1 to ProcessIterationCount

Dim agentProcIDs
agentProcIDs = "|"

' Step 1: Get all SCOM Processes
Dim oProcess, oProcessList
' Execute the query multiple times in case of failure
For counter = 1 to retryAttempts
Set oProcessList = oWMIService.ExecQuery("SELECT ProcessId, ParentProcessId, Name FROM Win32_Process")
If (IsListEmpty(oProcessList) = False) Then
Exit For
End If
Next

If (IsListEmpty(oProcessList) = False) Then

' Step 2: Get the Health Service and Monitoring Host objects
For Each oProcess in oProcessList
If IsObjectUnallocated(oProcess) = False Then
If ((InStr(oProcess.Name, "HealthService") &gt; 0) OR (InStr(oProcess.Name, "MonitoringHost") &gt; 0)) AND InStr(agentProcIDs, "|" &amp; oProcess.ProcessId &amp; "|") = 0 Then
agentProcIDs = agentProcIDs &amp; oProcess.ProcessId &amp; "|"
End If
End If
Next

'Step 3: Get all the child processes
Dim childFound
childFound = True
' While a new child is found, re-iterate the list to find its child
Do While childFound = True
childFound = False
For Each oProcess in oProcessList
If IsObjectUnallocated(oProcess) = False Then
' If parent process is in the agentProcIDs list but the process itself is not, its a new child

'Filter out myself
If oProcess.ProcessId &lt;&gt; myProcessId Then
If (InStr(agentProcIDs, "|" &amp; oProcess.ParentProcessId &amp; "|") &gt; 0) AND (InStr(agentProcIDs, "|" &amp; oProcess.ProcessId &amp; "|") = 0) Then
agentProcIDs = agentProcIDs &amp; oProcess.ProcessId &amp; "|"
childFound = True
End If
End If
End If
Next
Loop

'Step 4: Get the total cpu percentage used for all the SCOM processes
Dim objRefresher, objRefreshableItem, totalPercentProcessorTime
Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
Set objRefreshableItem = objRefresher.AddEnum(oWMIService , "Win32_PerfFormattedData_PerfProc_Process")
totalPercentProcessorTime = 0

' Refresh to get accurate data
objRefresher.Refresh

' Iterate each process to add the percent processor time to the total
For Each oProcess in objRefreshableItem.ObjectSet
If InStr(agentProcIDs, "|" &amp; oProcess.IDProcess &amp; "|") &gt; 0 then
totalPercentProcessorTime = totalPercentProcessorTime + CDbl(GetProcessorTime(oProcess.IDProcess, oWMIService))

objRefresher.Refresh

If (RunAsDiagnostic = True) Then
procTime = CDbl(GetProcessorTime(oProcess.IDProcess, oWMIService))
sampleCount = sampleCount + 1
totalCount = totalCount + procTime

' Check for min value
If procTime &lt; min Then
min = procTime
End If

' Check for max value
If procTime &gt; max Then
max = procTime
End If

End If
End If
Next

' Delete the refresher object
objRefresher.DeleteAll

' Add the total percentage time to the final percentage time for averaging in the end
finalPercentProcessorTime = finalPercentProcessorTime + totalPercentProcessorTime
dataCount = dataCount + 1

End If

' Delaying each iteration by 3 seconds
WScript.Sleep 3000
Next

' Add the detailed analysis to the property bag
If (RunAsDiagnostic = True) Then
oPropertyBag.AddValue "SamplesTaken", ProcessIterationCount
oPropertyBag.AddValue "Average", CDbl(totalCount/sampleCount)
oPropertyBag.AddValue "Maximum", max
oPropertyBag.AddValue "Minimum", min
End If

' Calculate the final percentage processor time for all the SCOM processes
If dataCount &lt; 1 Then
dataCount = 1
End If
finalPercentProcessorTime = (finalPercentProcessorTime / dataCount) / procCount

End If

If (RunAsDiagnostic = False) Then
oPropertyBag.AddValue "SCOMpercentageCPUTime", finalPercentProcessorTime
End If
Call oAPI.Return(oPropertyBag)
End Sub
'Copyright (c) Microsoft Corporation. All rights reserved.

' Constants
Const SCOM_SUCCESS = 0
Const SCOM_ERROR = 1
Const SCOM_WARNING = 2
Const SCOM_INFORMATION = 4

Const HKEY_LOCAL_MACHINE = &amp;H80000002

Dim SCRIPT_EVENT_ID

' Library Initializer
Sub InitializeCommon(iScriptEventID)
'set the script event id
SCRIPT_EVENT_ID = iScriptEventID
End Sub


' Check the list for null or empty
Function IsListEmpty(ByVal oList)
IsListEmpty = (IsNull(oList) = True) OR (oList.Count &lt; 1)
End Function


' Check object for null, empty or nothing
Function IsObjectUnallocated(ByVal obj)
IsObjectUnallocated = IsNull(obj) OR IsEmpty(obj) OR (TypeName(obj) = "Nothing")
End Function


' Gets the length of an array
Function GetArrayLength(ByRef array)
GetArrayLength = UBound(array) + 1
End Function


' Get the Host Computer name
Function GetHostComputerName
Dim oNetwork
Set oNetwork = MOMCreateObject("WScript.Network")
GetHostComputerName = oNetwork.ComputerName
End Function


' Get the WMI object
Function GetWMIObject(ByVal namespace)
Dim oWMI

'get the object
On Error Resume Next
Set oWMI = GetObject(namespace)
If Err.Number &lt;&gt; 0 Or IsEmpty(oWMI) Then
ThrowScriptError "Unable to open WMI Namespace '" &amp; namespace &amp; "'. Check to see if the WMI service is enabled and running, and ensure this WMI namespace exists.", Err
End If
On Error Goto 0

Set GetWMIObject = oWMI
End Function


' Get Registry object
Function GetRegistryObject(ByVal computerName)
Set GetRegistryObject = GetWMIObject("winmgmts:\\" &amp; computerName &amp; "\root\default:StdRegProv")
End Function


' Creates an event and sends it back to the mom server without stopping the script.
Function ThrowScriptErrorNoAbort(ByVal message, ByVal oErr)
' Retrieve the name of this (running) script
Dim scriptFileName
scriptFileName = GetScriptName

If Not IsNull(oErr) Then
message = message &amp; " Cause: " &amp; oErr.Description
end if

On Error Resume Next
Dim oAPITemp
Set oAPITemp = CreateObject("MOM.ScriptAPI")
If Err.Number = 0 Then
oAPITemp.LogScriptEvent scriptFileName, SCRIPT_EVENT_ID, SCOM_ERROR, message
End If
On Error Goto 0
End Function


' Creates an error event, sends it back to the mom server, and stops the script.
Function ThrowScriptError(Byval message, ByVal oErr)
On Error Resume Next
ThrowScriptErrorNoAbort message, oErr
WScript.Quit
End Function


' Gets the script name
Function GetScriptName
Dim oFSO
Set oFSO = MOMCreateObject("Scripting.FileSystemObject")
GetScriptName = oFSO.GetFile(WScript.ScriptFullName).Name
set oFSO = nothing
End Function


' Creates an object
Function MOMCreateObject(ByVal name)
'create the object
On Error Resume Next
Set MOMCreateObject = CreateObject(name)
If Err.Number &lt;&gt; 0 Then
ThrowScriptError "Unable to create COM object '" &amp; name &amp; "'", Null
End If
On Error Goto 0
End Function

' Log the message
Sub Log(message, severity)
Dim oTempAPI, scriptName

'get script name
scriptName = GetScriptName

'create a temp mom api object
'(avoids having to pass the object every time or using a global)
Set oTempAPI = MOMCreateObject("MOM.ScriptAPI")

'log event
On Error Resume Next
Call oTempAPI.LogScriptEvent(scriptName, SCRIPT_EVENT_ID, severity, message)
On Error Goto 0
End Sub

</Script></ScriptBody>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</ProbeAction>
</MemberModules>
<Composition>
<Node ID="Probe"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
<InputType>System!System.BaseData</InputType>
</ProbeActionModuleType>