Cluster Disk Monitoring Script Data Source

Microsoft.Windows.Server.ClusterDisksMonitoring.DS.Moduletype (DataSourceModuleType)

This module collects performace counters for cluster disks on Windows Cluster.

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
OutputTypeSystem.Performance.Data

Member Modules:

ID Module Type TypeId RunAs 
DS DataSource Microsoft.Windows.TimedScript.PropertyBagProvider Default
InstanceFilter ConditionDetection System.ExpressionFilter Default
PerfMapper ConditionDetection System.Performance.DataGenericMapper Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
IntervalSecondsint$Config/IntervalSeconds$Interval Seconds
LogSuccessEventbool$Config/LogSuccessEvent$Log Successful Event
TimeoutSecondsint$Config/TimeoutSeconds$Timeout Seconds

Source Code:

<DataSourceModuleType ID="Microsoft.Windows.Server.ClusterDisksMonitoring.DS.Moduletype" Accessibility="Internal" Batching="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="IntervalSeconds" type="xsd:integer" minOccurs="1"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="SyncTime" type="xsd:string" minOccurs="1"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="LogSuccessEvent" type="xsd:boolean"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ScriptGroupId" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TargetComputer" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ClusterName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ClusterResourceName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="CounterName" type="xsd:string"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int"/>
<OverrideableParameter ID="LogSuccessEvent" Selector="$Config/LogSuccessEvent$" ParameterType="bool"/>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedScript.PropertyBagProvider">
<IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
<SyncTime>$Config/SyncTime$</SyncTime>
<ScriptName>Microsoft.Windows.Server.MonitorClusterDisks.vbs</ScriptName>
<Arguments>$Config/LogSuccessEvent$ "$Config/ScriptGroupId$" "$Config/TargetComputer$" "$Config/ClusterName$"</Arguments>
<ScriptBody><Script>Option Explicit
SetLocale("en-us")

Const SCRIPT_VERSION = "1.06"
Const LOG_SUCCESS_EVENT_PARAMETER_NAME = "LogSuccessEvent"
Const MP_ELEMENT_PARAMETER_NAME = "MP Element"
Const MANAGED_ENTITY_ID_PARAMETER_NAME = "Managed Entity"
Const TARGET_COMPUTER_PARAMETER_NAME = "Target Computer"
Const CLUSTER_NAME_PARAMETER_NAME = "Cluster Name"

'WMI constants
Const WMI_MSCLUSTER_NAMESPACE = "root\MSCluster"
Const WMI_CIMV2_NAMESPACE = "root\cimv2"
Const WMI_MSCLUSTER_CLUSTER_RESOURCE = "MSCluster_Resource"
Const WMI_CLUSTER_RESOURCE_TO_DISKPARTITION_ASSOCIATOR_CLASS = "MSCluster_ResourceToDiskPartition"

Const WMI_MSCLUSTER_CLUSTER_CLASS = "MSCluster_Cluster"
Const WMI_NAME_PROPERTY_NAME = "Name"
Const WMI_PATH_PROPERTY_NAME = "Path"
Const WMI_FILESYSTEM_PROPERTY_NAME = "FileSystem"
Const WMI_TOTALSIZE_PROPERTY_NAME = "TotalSize"
Const WMI_FREESPACE_PROPERTY_NAME = "FreeSpace"
Const WMI_VOLUMELABEL_PROPERTY_NAME = "VolumeLabel"

'State property bag constants
Const STATE_DATA_TYPE = 3
Const STATE_PROPERTY_NAME = "State"

'Performance property bag constants
Const INSTANCE_NAME = "ClusterDiskName"
Const PERFORMANCE_DATA_TYPE = 2
Const PERFORMANCE_OBJECT_NAME = "PerfObject"
Const PERFORMANCE_COUNTER_NAME = "PerfCounter"
Const PERFORMANCE_INSTANCE_NAME = "PerfInstance"
Const PERFORMANCE_VALUE_NAME = "PerfValue"
Const PERF_OBJECT_CSV = "Cluster Disk"
Const PERF_COUNTER_TOTAL_SIZE_MB = "Total size / MB"
Const PERF_COUNTER_FREE_SPACE_MB = "Free space / MB"
Const PERF_COUNTER_FREE_SPACE_PERCENT = "Free space / Percent"

Const PERF_COUNTER_DISK_READS_PER_SECOND = "Disk Reads/sec"
Const PERF_COUNTER_CURRENT_DISK_QUEUE_LENGTH = "Current Disk Queue Length"
Const PERF_COUNTER_PERCENT_LOGICAL_DISK_IDLE_TIME = "% Idle Time"
Const PERF_COUNTER_AVG_DISK_QUEUE_LENGTH = "Avg. Disk Queue Length"
Const PERF_COUNTER_AVG_LOGICAL_DISK_READ_QUEUE = "Avg. Disk Read Queue Length"
Const PERF_COUNTER_DISK_BYTES_PER_SECOND = "Disk Bytes/sec"
Const PERF_COUNTER_AVG_DISK_SECONDS_PER_TRANSFER = "Avg. Disk sec/Transfer"
Const PERF_COUNTER_AVG_DISK_SECONDS_PER_READ = "Avg. Disk sec/Read"
Const PERF_COUNTER_AVG_DISK_WRITE_QUEUE_LENGTH = "Avg. Disk Write Queue Length"
Const PERF_COUNTER_LOGICAL_DISK_SPLIT_IO_PER_SECOND = "Split IO/Sec"
Const PERF_COUNTER_LOGICAL_DISK_WRITE_BYTES_PER_SECOND = "Disk Write Bytes/sec"
Const PERF_COUNTER_DISK_WRITES_PER_SECOND = "Disk Writes/sec"
Const PERF_COUNTER_DISK_READ_BYTES_PER_SECOND = "Disk Read Bytes/sec"
Const PERF_COUNTER_AVG_DISK_SECONDS_PER_WRITE = "Avg. Disk sec/Write"


'Event constants
Const EVENT_TYPE_SUCCESS = 0
Const EVENT_TYPE_ERROR = 1
Const EVENT_TYPE_WARNING = 2
Const EVENT_TYPE_INFORMATION = 4

Const EVENT_ID_SUCCESS = 1000 'Use IDs in the range 1 - 1000
Const EVENT_ID_SCRIPTERROR = 999 'Then you can use eventcreate.exe to test the MP

'Global vars
Dim mblnLogSuccessEvent 'As Boolean
Dim mstrIdentifier 'As String


Call Main

'*********************************************************************************************
' PROCEDURE: Main
' DESCRIPTION: Reads the script parameters and creates the cluster disk monitoring data.
' PARAMETERS: void
'*********************************************************************************************
Private Sub Main()

' Targeted at Microsoft.Windows.Cluster.VirtualServer (based on Microsoft.Windows.Server.Computer)
Dim objFSO 'As Scripting.FileSystemObject
Dim boolNoMonitoredClusterDiskAvailable

Dim strTargetComputer 'As String '= oArgs(6)
Dim strClusterName 'As String '= oArgs(7)
Dim objMomScriptAPI 'As MOM.ScriptAPI
Dim blnSuccess 'As Boolean
Dim strErrorMessage

On Error Resume Next
Err.Clear

Set objMomScriptAPI = CreateObject("MOM.ScriptAPI")
If Err.Number &lt;&gt; 0 Then
Exit Sub
End If

If Not GetScriptParameters(strTargetComputer, strClusterName) Then
' If the script is called without the required arguments,
' create an information event and then quit.
strErrorMessage = "The script was called with fewer than four arguments or the arguments could not be parsed."
Call LogScriptEvent(0, EVENT_ID_SCRIPTERROR, EVENT_TYPE_WARNING, strErrorMessage,objMomScriptAPI)
WScript.Quit(-1)
End If

'Monitor instances
blnSuccess = MonitorClusterDisks(strTargetComputer, strClusterName, objMomScriptAPI, boolNoMonitoredClusterDiskAvailable)

If blnSuccess Then
If mblnLogSuccessEvent Then
strErrorMessage = "Script executed successfully."
Call LogScriptEvent(0, EVENT_ID_SUCCESS, EVENT_TYPE_INFORMATION, strErrorMessage,objMomScriptAPI)
End If
'Return the typed property bags
If boolNoMonitoredClusterDiskAvailable = true Then
CreateEmptyTypedPropertyBag(objMomScriptAPI)
End If

Else
CreateEmptyTypedPropertyBag(objMomScriptAPI)
strErrorMessage = "TAn error occurred while running script"
Call LogScriptEvent(0, EVENT_ID_SCRIPTERROR, EVENT_TYPE_WARNING, strErrorMessage,objMomScriptAPI)
End If

Call objMomScriptAPI.ReturnItems

Set objMomScriptAPI = Nothing
End Sub



'****************************************************************************************************************
' FUNCTION: MonitorClusterDisks
' DESCRIPTION: Creates monitoring data for all instances of the class 'Microsoft.Windows.Server.ClusterDisksMonitoring.ClusterDisk' using WMI.
' PARAMETERS: IN String strTargetComputer: principal name of the targeted 'Microsoft.Windows.Cluster.VirtualServer' instance.
' IN String strClusterName: the cluster containing the cluster shared volume
' RETURNS: Boolean: True if successful
'****************************************************************************************************************
Private Function MonitorClusterDisks(ByRef strTargetComputer, ByRef strClusterName, ByRef objMomScriptAPI, ByRef boolNoMonitoredClusterDiskAvailable) 'As Boolean

Dim objMSClusterSWbemServices 'As SWbemServices
Dim objClusterResources 'As SWbemObject
Dim objClusterResource 'As SWbemObject
Dim objClusterDisk 'As SWbemObject
Dim objClusterDiskPartition 'As SWbemObject
Dim objClusterDiskPartitions 'As SWbemObject
Dim objCIMV2SWbemServices 'As SWbemServices

Dim blnSuccess 'As Boolean
Dim strOSVersion
Dim strWMIQuery
Dim strWMICIMQuery
Dim InstancesCount
Dim objLogicalDisksPerfs
Dim objLogicalDisksPerfsTemp

InstancesCount = 0
MonitorClusterDisks = false
blnSuccess = true
boolNoMonitoredClusterDiskAvailable = true
Set objLogicalDisksPerfs = CreateObject("Scripting.Dictionary")

'Connect to WMI NS \\.\root\MSCluster
If Not ConnectToWbemNS(".", WMI_MSCLUSTER_NAMESPACE, objMSClusterSWbemServices) Then
boolNoMonitoredClusterDiskAvailable = true
Exit Function
End If

Call ConnectToWbemNS(".",WMI_CIMV2_NAMESPACE,objCIMV2SWbemServices)

On Error Resume Next

Err.Clear
strOSVersion = GetRegistryKeyValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\", "CurrentVersion")

'Adding OS Validation to use propert WMI query to get correct instances
'ResourceClass and IsClusterSharedVolume properties are not available in Windows 2008 OS, only 2008 R2 and beyond.
If (0 = Len(strOSVersion)) Then
Exit Function
End If

If (strOSVersion = "6.0") Then
strWMIQuery = "select * from " &amp; WMI_MSCLUSTER_CLUSTER_RESOURCE
'&amp; " where CoreResource = FALSE"
Else
strWMIQuery = "select * from " &amp; WMI_MSCLUSTER_CLUSTER_RESOURCE &amp; " where ResourceClass = 1 and IsClusterSharedVolume = FALSE"
'"and CoreResource = FALSE"
End If

strWMICIMQuery = "Select * from Win32_perfrawdata_perfdisk_LogicalDisk"

Set objClusterResources = objMSClusterSWbemServices.ExecQuery(strWMIQuery)
If (Err.Number &lt;&gt; 0 Or Not HasValue(objClusterResources) ) Then
Exit Function
End If

Set objLogicalDisksPerfsTemp = objCIMV2SWbemServices.ExecQuery(strWMICIMQuery)
Call ObjLogicalDiskPerfsToHashTable(objLogicalDisksPerfsTemp,objLogicalDisksPerfs)

'Loop through all returned cluster resources
For Each objClusterResource In objClusterResources
'Get the associated disk partition
Set objClusterDiskPartitions = objClusterResource.Associators_(WMI_CLUSTER_RESOURCE_TO_DISKPARTITION_ASSOCIATOR_CLASS, "", "", "", False, False, "", "", 0)
For Each objClusterDiskPartition In objClusterDiskPartitions
blnSuccess = CreateMonitoringData(objClusterDisk, objClusterDiskPartition, objClusterResource,strTargetComputer, strClusterName, objMomScriptAPI,objLogicalDisksPerfs)
If (false = blnSuccess) Then
InstancesCount = 1
Else
If (0 = InstancesCount) Then
InstancesCount = 2
End If
End If
Next 'objClusterDiskPartition
Next 'objClusterResource
If (InstancesCount = 2) Then
boolNoMonitoredClusterDiskAvailable = false
End If

MonitorClusterDisks = True

Set objClusterDiskPartitions = Nothing
Set objClusterResources = Nothing

On Error Goto 0
End Function

'****************************************************************************************************************
' FUNCTION: CreateMonitoringData
' DESCRIPTION: Create monitoring data for a cluster shared volume.
'
' PARAMETERS: IN Object objClusterResource: the cluster disks as SWbemObject of type MSCluster_Disk.
' IN Object objClusterDiskPartition: the associated disk partition as SWbemObject of type MSCluster_DiskPartition.
' IN Object objClusterResource: the associated cluster resource as SWbemObject of type MSCluster_Resource.
' IN String strTargetComputer: the principal name of the targeted cluster virtual server hosting the cluster shared volume,
' i.e. the cluster name and not the current owner!
' IN String strClusterName: the cluster containing the cluster shared volume
' RETURNS: Boolean: True if successful
'****************************************************************************************************************
Private Function CreateMonitoringData(ByRef objClusterDisk, ByRef objClusterDiskPartition, ByRef objClusterResource, _
ByRef strTargetComputer, ByRef strClusterName, ByRef objMomScriptAPI,ByRef objLogicalDisksPerfs) 'As Boolean

'Create performance data
Dim strPartitionName 'As String
Dim strPartitionPath
CreateMonitoringData = False

On Error Resume Next
Err.Clear
strPartitionPath=objClusterDiskPartition.Properties_(WMI_PATH_PROPERTY_NAME)
strPartitionName = objClusterResource.Properties_(WMI_NAME_PROPERTY_NAME) &amp; "_" &amp; objClusterDiskPartition.Properties_(WMI_PATH_PROPERTY_NAME)

'Total Size /MB
Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_TOTAL_SIZE_MB, strPartitionName, _
objClusterDiskPartition.Properties_(WMI_TOTALSIZE_PROPERTY_NAME), strPartitionName, objMomScriptAPI)

'Free Space /MB
Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_FREE_SPACE_MB, strPartitionName, _
objClusterDiskPartition.Properties_(WMI_FREESPACE_PROPERTY_NAME), strPartitionName, objMomScriptAPI)

'Free Space /%
Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_FREE_SPACE_PERCENT, strPartitionName, _
Round(CLng(objClusterDiskPartition.Properties_(WMI_FREESPACE_PROPERTY_NAME)) / CLng(objClusterDiskPartition.Properties_(WMI_TOTALSIZE_PROPERTY_NAME)) * 100), _
strPartitionName, objMomScriptAPI)




Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_DISK_READS_PER_SECOND, strPartitionName, objLogicalDisksPerfs(strPartitionPath).DiskReadsPersec, strPartitionName, objMomScriptAPI) 'Disk Reads/sec


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_CURRENT_DISK_QUEUE_LENGTH, strPartitionName, objLogicalDisksPerfs(strPartitionPath).CurrentDiskQueueLength, strPartitionName, objMomScriptAPI) 'Current Disk Queue Length


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_PERCENT_LOGICAL_DISK_IDLE_TIME, strPartitionName, objLogicalDisksPerfs(strPartitionPath).PercentIdleTime, strPartitionName, objMomScriptAPI) '% Idle Time


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_AVG_DISK_QUEUE_LENGTH, strPartitionName, objLogicalDisksPerfs(strPartitionPath).AvgDiskQueueLength, strPartitionName, objMomScriptAPI) 'Avg. Disk Queue Length


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_AVG_LOGICAL_DISK_READ_QUEUE, strPartitionName, objLogicalDisksPerfs(strPartitionPath).AvgDiskReadQueueLength, strPartitionName, objMomScriptAPI) 'Avg. Disk Read Queue Length


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_DISK_BYTES_PER_SECOND, strPartitionName, objLogicalDisksPerfs(strPartitionPath).DiskBytesPersec, strPartitionName, objMomScriptAPI) 'Disk Bytes/sec


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_AVG_DISK_SECONDS_PER_TRANSFER, strPartitionName, objLogicalDisksPerfs(strPartitionPath).AvgDisksecPerTransfer, strPartitionName, objMomScriptAPI) 'Avg. Disk sec/Transfer


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_AVG_DISK_SECONDS_PER_READ, strPartitionName, objLogicalDisksPerfs(strPartitionPath).AvgDisksecPerRead, strPartitionName, objMomScriptAPI) 'Avg. Disk sec/Read


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_AVG_DISK_WRITE_QUEUE_LENGTH, strPartitionName, objLogicalDisksPerfs(strPartitionPath).AvgDiskWriteQueueLength, strPartitionName, objMomScriptAPI) 'Avg. Disk Write Queue Length


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_LOGICAL_DISK_SPLIT_IO_PER_SECOND, strPartitionName, objLogicalDisksPerfs(strPartitionPath).SplitIOPerSec, strPartitionName, objMomScriptAPI) 'Split IO/Sec


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_LOGICAL_DISK_WRITE_BYTES_PER_SECOND, strPartitionName, objLogicalDisksPerfs(strPartitionPath).DiskWriteBytesPersec, strPartitionName, objMomScriptAPI) 'Disk Write Bytes/sec


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_DISK_WRITES_PER_SECOND, strPartitionName, objLogicalDisksPerfs(strPartitionPath).DiskWritesPersec, strPartitionName, objMomScriptAPI) 'Disk Writes/sec


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_DISK_READ_BYTES_PER_SECOND, strPartitionName, objLogicalDisksPerfs(strPartitionPath).DiskReadBytesPersec, strPartitionName, objMomScriptAPI) 'Disk Read Bytes/sec


Call CreatePerformanceTypedPropertyBag(PERF_OBJECT_CSV, PERF_COUNTER_AVG_DISK_SECONDS_PER_WRITE, strPartitionName, objLogicalDisksPerfs(strPartitionPath).AvgDisksecPerWrite, strPartitionName, objMomScriptAPI) 'Avg. Disk sec/Write


If (0 = Err.Number) Then
CreateMonitoringData = True
End If

On Error Goto 0
End Function

'******************************************************************************
' FUNCTION: GetScriptParameters
' DESCRIPTION: Reads the script's parameters
' and sets the global variables.
'
' PARAMETERS: OUT String strTargetComputer: Principal name of executing computer
' (-Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName-)
' OUT String strClusterName: Cluster name
' RETURNS: Boolean: True if successful
'******************************************************************************
Private Function GetScriptParameters(ByRef strTargetComputer, ByRef strClusterName) 'As Boolean

Dim objArguments

On Error Resume Next

'cmdline: &lt;script&gt; True|False &lt;path to debug log&gt; True|False &lt;script id&gt; .MPElement. .Target/Id. .Target/Property[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName.
Set objArguments = WScript.Arguments
If objArguments.Count &lt; 4 Then Exit Function

Err.Clear
'Get parameters and set global variables
mblnLogSuccessEvent = CBool(objArguments(0))
If (Err.Number &lt;&gt; 0 ) Then
mblnLogSuccessEvent = False
End If

mstrIdentifier = Replace(objArguments(1), Chr(34), "")
strTargetComputer = Replace(objArguments(2), Chr(34), "")
strClusterName = Replace(objArguments(3), Chr(34), "")

If Len(strTargetComputer) &gt; 0 And Len(strClusterName) &gt; 0 Then GetScriptParameters = True
On Error Goto 0
End Function



'***************************************************************************************
' PROCEDURE: CreatePerformanceTypedPropertyBag
' DESCRIPTION: Generates a performance typed property bag and adds it to the script's XML output.
' PARAMETERS: IN String strObjectName: name of the performance object
' IN String strCounterName: name of the performance counter
' IN String strInstanceName: name of the performance counter in instance
' IN Variant varValue: value of the performance counter
' IN String strCSVInstanceName: Friendly volume name of the cluster shared volume
' IN Object objMomScriptAPI: initialised MOM.ScriptAPI object
'***************************************************************************************
Sub CreatePerformanceTypedPropertyBag(ByRef strObjectName, ByRef strCounterName, ByRef strInstanceName, _
ByRef varValue, ByRef strCSVInstanceName, ByRef objMomScriptAPI)

Dim objTypedPropertyBag 'As MOM.ScriptAPI.TypedPropertyBag


'Create a new typed property bag of the performance data type
Set objTypedPropertyBag = objMomScriptAPI.CreateTypedPropertyBag(PERFORMANCE_DATA_TYPE)

'Add the values for the perf counter's object name, counter name, instance name and the value)
Call objTypedPropertyBag.AddValue(PERFORMANCE_OBJECT_NAME, CStr(strObjectName))
Call objTypedPropertyBag.AddValue(PERFORMANCE_COUNTER_NAME, CStr(strCounterName))
Call objTypedPropertyBag.AddValue(PERFORMANCE_INSTANCE_NAME, CStr(strInstanceName))
Call objTypedPropertyBag.AddValue(PERFORMANCE_VALUE_NAME, CStr(varValue))

'Necessary information for the property bag data source filter condition
'to enable Agent cook down
Call objTypedPropertyBag.AddValue(INSTANCE_NAME, CStr(strCSVInstanceName))

'Add the property bag to the script's XML output
Call objMomScriptAPI.AddItem(objTypedPropertyBag)

End Sub

'***************************************************************************************
' PROCEDURE: CreateEmptyTypedPropertyBag
' DESCRIPTION: Generates a empty performance typed property bag and adds it to the script's XML output.
' PARAMETERS: IN Object objMomScriptAPI: initialised MOM.ScriptAPI object
'***************************************************************************************
Sub CreateEmptyTypedPropertyBag(ByRef objMomScriptAPI)

Dim objTypedPropertyBag 'As MOM.ScriptAPI.TypedPropertyBag

'Create a new typed property bag of the performance data type
Set objTypedPropertyBag = objMomScriptAPI.CreateTypedPropertyBag(PERFORMANCE_DATA_TYPE)

Call objTypedPropertyBag.AddValue(PERFORMANCE_OBJECT_NAME, "EMPTY")
Call objTypedPropertyBag.AddValue(PERFORMANCE_COUNTER_NAME, "EMPTY")
Call objTypedPropertyBag.AddValue(PERFORMANCE_INSTANCE_NAME, "EMPTY")
Call objTypedPropertyBag.AddValue(PERFORMANCE_VALUE_NAME, "EMPTY")

'Add the property bag to the script's XML output
Call objMomScriptAPI.AddItem(objTypedPropertyBag)

End Sub

Private Function GetLogScriptName()

GetLogScriptName = "-- Cluster Disks Monitoring Script -- " &amp; vbCrLf &amp; vbCrLf &amp; "Script name: " &amp; WScript.ScriptName &amp; vbCrLf &amp; "Version: " &amp; SCRIPT_VERSION &amp; vbCrLf

End Function


Private Function ObjLogicalDiskPerfsToHashTable(ByRef objLogicalDisksPerfsTemp, ByRef objLogicalDisksPerfs) 'As Boolean
Dim objLogicalDiskPerfTemp

On Error Resume Next

For Each objLogicalDiskPerfTemp In objLogicalDisksPerfsTemp
If(not (objLogicalDisksPerfs.Exists(objLogicalDiskPerfTemp.Name))) then
objLogicalDisksPerfs.Add objLogicalDiskPerfTemp.Name,objLogicalDiskPerfTemp
End If
Next

On Error Goto 0
End Function'****************************************************************************************************************
' FUNCTION: GetClusterName
' DESCRIPTION: Returns the cluster name of the given cluster virtual name
' PARAMETERS: OUT String strClusterName: string to return the cluster name
' RETURNS: Boolean: True if successful
'****************************************************************************************************************
Private Function GetClusterName(ByRef strClusterName) 'As Boolean

Dim objMSClusterSWbemServices 'As SWbemServices
Dim strWQLQuery 'As String
Dim objClusters 'As SWbemObjectSet
Dim objCluster 'As SWbemObject
Dim bResult

GetClusterName = False
bResult = GetClusterNameFromRegistry(strClusterName)

If (True = bResult And Len(strClusterName) &gt; 0 ) Then
GetClusterName = bResult
Exit Function
End If

On Error Resume Next
Err.Clear

'Connect to WMI NS \\.\root\MSCluster
If ConnectToWbemNS(".", WMI_MSCLUSTER_NAMESPACE, objMSClusterSWbemServices) Then

strWQLQuery = "select * from " &amp; WMI_MSCLUSTER_CLUSTER_CLASS
Set objClusters = objMSClusterSWbemServices.ExecQuery(strWQLQuery)
If HasValue(objClusters) Then
For Each objCluster In objClusters
strClusterName = objCluster.Name
Next 'objCluster

If Len(strClusterName) &gt; 0 Then GetClusterName = True
End If
Set objClusters = Nothing

End If

On Error Goto 0

End Function


'****************************************************************************************************************
' FUNCTION: GetClusterNameFromRegistry
' DESCRIPTION: Returns the cluster name of the given cluster virtual name
' PARAMETERS: OUT String strClusterName: string to return the cluster name
' RETURNS: Boolean: True if successful
'****************************************************************************************************************
Private Function GetClusterNameFromRegistry(ByRef strClusterName) 'As Boolean

Dim objReg 'Registry
Const ClusterNamePath = "HKLM\Cluster\"

strClusterName = GetRegistryKeyValue(ClusterNamePath,"ClusterName")
GetClusterNameFromRegistry = Len(strClusterName) &gt; 0

End Function

'****************************************************************************************************************
' FUNCTION: GetComputerName ' DESCRIPTION: return short computername
' PARAMETERS: IN String strTargetComputer: principal name of the targeted 'Microsoft.Windows.Cluster.VirtualServer' instance.
' RETURNS: Integer: 0 if successful and 1 if fails
'****************************************************************************************************************
Private Function GetComputerName(strTargetComputer)

Dim strComputerName
Dim PointPos

PointPos = InStr(strTargetComputer, ".")
If PointPos &gt; 0 Then
strComputerName = LCase(Left(strTargetComputer, PointPos - 1))
Else
strComputerName = LCase(strTargetComputer)
End If

GetComputerName = strComputerName
End Function

'******************************************************************************
' FUNCTION: ConnectToWbemNs
' DESCRIPTION: Connects to a WMI namespace
' PARAMETERS: IN String strServerName: name of the computer. If empty the local computer will be used.
' IN String strNameSpace: WMI namespace
' OUT Object objSWbemServices: WbemScripting.SWbemServices object connected to the given
' namespace on the given server
' RETURNS: Boolean: True if successful
'******************************************************************************
Private Function ConnectToWbemNS(ByRef strServerName, ByRef strNameSpace, ByRef objSWbemServices) 'As Boolean

ConnectToWbemNS = False
Dim objSWbemLocator 'as WbemScripting.SWbemLocator
Set objSWbemServices = Nothing

On Error Resume Next
'Create a new WMI Locator object
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")

IF HasValue(objSWbemLocator) Then
'Connect to WMI namespace on strServerName computer and create WMI Services object
Set objSWbemServices = objSWbemLocator.ConnectServer(strServerName, strNameSpace)
END IF

'If object is initialised function will be successful
ConnectToWbemNS = HasValue(objSWbemServices)

On Error Goto 0

End Function

Private Function HasValue(Value)

Dim bNothing

bNothing = false

IF ( IsObject(Value) ) THEN
IF (Nothing is Value) THEN
bNothing = true
END IF
END IF

HasValue = Not ( IsEmpty(Value) or bNothing or IsNull(Value) )
End Function

'****************************************************************************************************************
' FUNCTION: GetRegistryKeyValue
' DESCRIPTION: Get Registry Key value.
' PARAMETERS: IN String keyPath: Path to search in registry.
' IN String Key: key to return value from
' RETURNS: string: Value if successful
'****************************************************************************************************************
Function GetRegistryKeyValue(ByVal keyPath, ByVal key)
Dim oReg, strKeyValue

strKeyValue = ""
GetRegistryKeyValue = strKeyValue
On Error Resume Next
Err.Clear
Set oReg = CreateObject("WScript.Shell")
If Err.Number &lt;&gt; 0 Then
Err.Clear
Exit Function
End If
strKeyValue = oReg.RegRead(keyPath &amp; key)
If Err.Number &lt;&gt; 0 Then
Err.Clear
Exit Function
End If

GetRegistryKeyValue = strKeyValue

' resume error
On Error Goto 0

End Function

'******************************************************************************
' Subroutine: LogScriptEvent
' DESCRIPTION: Logging events to EventSource
' PARAMETERS: IN Integer LogType: 0 - MomScriptApi; 1 - File, 2 - Screen .
' IN String Message: Event Description
' OUT Object objSWbemServices: WbemScripting.SWbemServices object connected to the given
' namespace on the given server
' RETURNS: Boolean: True if successful
'******************************************************************************

Sub LogScriptEvent(LogType,EventId,EventLevel,Message,objMomScriptAPI)

Dim strMessage
Dim sDate
Dim LogScriptName

On Error Resume Next
If (0 = LogType) Then
If (Not HasValue(objMomScriptAPI)) Then
Exit Sub
End If
LogScriptName = GetLogScriptName()
Call objMomScriptAPI.LogScriptEvent(LogScriptName,EventId,EventLevel,Message)

Else
sDate = Now()
strMessage = "" &amp; sDate &amp; Message

If (1 = LogType) Then
WScript.Echo strMessage
End If

End If

On Error Goto 0
End Sub
</Script></ScriptBody>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</DataSource>
<ConditionDetection ID="PerfMapper" TypeID="SystemPerf!System.Performance.DataGenericMapper">
<ObjectName>$Data/Property[@Name='PerfObject']$</ObjectName>
<CounterName>$Data/Property[@Name='PerfCounter']$</CounterName>
<InstanceName>$Data/Property[@Name='PerfInstance']$</InstanceName>
<Value>$Data/Property[@Name='PerfValue']$</Value>
</ConditionDetection>
<ConditionDetection ID="InstanceFilter" TypeID="System!System.ExpressionFilter">
<Expression>
<And>
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="String">Property[@Name='PerfInstance']</XPathQuery>
</ValueExpression>
<Operator>Equal</Operator>
<ValueExpression>
<Value Type="String">$Config/ClusterResourceName$</Value>
</ValueExpression>
</SimpleExpression>
</Expression>
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="String">Property[@Name='PerfCounter']</XPathQuery>
</ValueExpression>
<Operator>Equal</Operator>
<ValueExpression>
<Value Type="String">$Config/CounterName$</Value>
</ValueExpression>
</SimpleExpression>
</Expression>
</And>
</Expression>
</ConditionDetection>
</MemberModules>
<Composition>
<Node ID="PerfMapper">
<Node ID="InstanceFilter">
<Node ID="DS"/>
</Node>
</Node>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>SystemPerf!System.Performance.Data</OutputType>
</DataSourceModuleType>