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

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

' 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
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
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(oProcess.PercentProcessorTime)

If (RunAsDiagnostic = True) Then
procTime = CDbl(CDbl(oProcess.PercentProcessorTime)/procCount)
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
If totalPercentProcessorTime &gt; 0 Then
finalPercentProcessorTime = finalPercentProcessorTime + totalPercentProcessorTime
dataCount = dataCount + 1
End If

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>