Cluster Disk Monitoring Script Data Source

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

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
OutputTypeSystem.Performance.Data

Member Modules:

ID Module Type TypeId RunAs 
Scheduler DataSource System.Scheduler Default
DS ProbeAction Microsoft.Windows.PowerShellPropertyBagProbe Default
InstanceFilter ConditionDetection System.ExpressionFilter Default
PerfMapper ConditionDetection System.Performance.DataGenericMapper Default

Overrideable Parameters:

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

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="Scheduler" TypeID="System!System.Scheduler">
<Scheduler>
<SimpleReccuringSchedule>
<Interval>$Config/IntervalSeconds$</Interval>
<SyncTime>$Config/SyncTime$</SyncTime>
</SimpleReccuringSchedule>
<ExcludeDates/>
</Scheduler>
</DataSource>
<ProbeAction ID="DS" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagProbe">
<ScriptName>Microsoft.Windows.Server.MonitorClusterDisks.ps1</ScriptName>
<ScriptBody><Script>

param ($mblnLogSuccessEvent, $mstrIdentifier, $strTargetComputer, $strClusterName)

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

#WMI constants
$WMI_MSCLUSTER_NAMESPACE = "root\MSCluster"
$WMI_CIMV2_NAMESPACE = "root\cimv2"
$WMI_MSCLUSTER_CLUSTER_RESOURCE = "MSCluster_Resource"
$WMI_CLUSTER_RESOURCE_TO_DISK_ASSOCIATOR_CLASS = "MSCluster_ResourceToDisk"
$WMI_CLUSTER_DISKPARTITION_TO_DISK_ASSOCIATOR_CLASS = "MSCluster_DiskToDiskPartition"

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

#State property bag constants
$STATE_DATA_TYPE = 3
$STATE_PROPERTY_NAME = "State"
$STATE_NTFS_NAME = "NTFSIsDirty"
$STATE_GOOD = "GOOD"
$STATE_BAD = "BAD"

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

#Event constants
$EVENT_TYPE_SUCCESS = 0
$EVENT_TYPE_ERROR = 1
$EVENT_TYPE_WARNING = 2
$EVENT_TYPE_INFORMATION = 4

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

#Scripting.FileSystemObject constants
$FOR_READING = 1 #Open a file for reading only. You can#t write to this file.
$FOR_WRITING = 2 #Open a file for writing.
$FOR_APPENDING = 8 #Open a file and write to the end of the file.

$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

#Global vars
#$mblnLogSuccessEvent #As String(ToBoolean) (passed in as parameter of script)
#$mstrIdentifier #As String (passed in as parameter of script)

#*********************************************************************************************
# PROCEDURE: Main
# DESCRIPTION: Reads the script parameters and creates the cluster disk monitoring data.
# PARAMETERS: void
#*********************************************************************************************
Function Main()
{
$objMomScriptAPI = New-Object -comObject MOM.ScriptAPI

#Monitor instances
$boolNoMonitoredClusterDiskAvailable = $false
$list = MonitorClusterDisks $strTargetComputer $strClusterName $objMomScriptAPI ([ref]$boolNoMonitoredClusterDiskAvailable)
$blnSuccess = $false
if($list -ne $null){
$blnSuccess = $true
}
foreach($data in $list)
{
#Add the values for the perf counter#s object name, counter name, instance name and the value)
if($data.$PERFORMANCE_OBJECT_NAME -eq $null)
{
continue
}
$blnSuccess = $true
$objTypedPropertyBag = $objMomScriptAPI.CreateTypedPropertyBag($PERFORMANCE_DATA_TYPE)
$objTypedPropertyBag.AddValue($PERFORMANCE_OBJECT_NAME, $data.$PERFORMANCE_OBJECT_NAME)
$objTypedPropertyBag.AddValue($PERFORMANCE_COUNTER_NAME, $data.$PERFORMANCE_COUNTER_NAME)
$objTypedPropertyBag.AddValue($PERFORMANCE_INSTANCE_NAME, $data.$PERFORMANCE_INSTANCE_NAME)
if(($data.$PERFORMANCE_VALUE_NAME -eq $null) -or ($data.$PERFORMANCE_VALUE_NAME -eq "")){
$objTypedPropertyBag.AddValue($PERFORMANCE_VALUE_NAME, 0)
}else{
$objTypedPropertyBag.AddValue($PERFORMANCE_VALUE_NAME, $data.$PERFORMANCE_VALUE_NAME)
}
#Necessary information for the property bag data source filter condition
#to enable Agent cook down
$objTypedPropertyBag.AddValue($INSTANCE_NAME, $data.$INSTANCE_NAME)
$objTypedPropertyBag
}

if ($blnSuccess)
{
if ([System.Convert]::ToBoolean($mblnLogSuccessEvent) -eq $true)
{
$objMomScriptAPI.LogScriptEvent((Split-Path $MyInvocation.ScriptName -Leaf), $EVENT_ID_SUCCESS, $EVENT_TYPE_INFORMATION, "-- Cluster Disks Monitoring Script -- Script executed successfully.")
}
}
else
{
$objMomScriptAPI.LogScriptEvent((Split-Path $MyInvocation.ScriptName -Leaf), $EVENT_ID_SCRIPTERROR, $EVENT_TYPE_WARNING, "-- Cluster Disks Monitoring Script -- An error occurred while running the script.")
}

if ($blnSuccess -and $boolNoMonitoredClusterDiskAvailable)
{
#Create an Empty typed property bag of the performance data type
$objTypedPropertyBag = $objMomScriptAPI.CreateTypedPropertyBag($PERFORMANCE_DATA_TYPE)

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

#Add the property bag to the script#s XML output
$objTypedPropertyBag
}
}

#****************************************************************************************************************
# 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
#****************************************************************************************************************
Function MonitorClusterDisks($strTargetComputer, $strClusterName, $objMomScriptAPI, [ref]$boolNoMonitoredClusterDiskAvailable) #As Boolean
{
$InstancesCount = 0

#Connect to WMI NS \\.\root\MSCluster
$error.Clear()
# !!! Refactoring comment:
# Original VBScript only tries to connect to the namespace. Piping to get only the first one saves time.
if($useCIM){
$oWMI = Get-CimClass -Namespace $WMI_MSCLUSTER_NAMESPACE -ErrorAction SilentlyContinue | select -First 1
}else{
$oWMI = Get-WMIObject -Namespace $WMI_MSCLUSTER_NAMESPACE -Class $WMI_MSCLUSTER_CLUSTER_RESOURCE -ErrorAction SilentlyContinue | select -First 1
}
if ($error.Count -eq 0)
{
$blnSuccess = $true
$strOSVersion = (Get-ItemProperty -Path "HKLM:\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 ($strOSVersion -eq "6.0")
{
$strWMIQuery = "select * from " + $WMI_MSCLUSTER_CLUSTER_RESOURCE + " where CoreResource = FALSE"
}
else
{
$strWMIQuery = "select * from " + $WMI_MSCLUSTER_CLUSTER_RESOURCE + " where ResourceClass = 1 and IsClusterSharedVolume = FALSE and CoreResource = FALSE"
}
if($useCIM){
$objClusterResources = Get-CimInstance -Namespace $WMI_MSCLUSTER_NAMESPACE -Query $strWMIQuery
}else{
$objClusterResources = Get-WMIObject -Namespace $WMI_MSCLUSTER_NAMESPACE -Query $strWMIQuery
}
#Loop through all returned cluster shared volumes
foreach ($objClusterResource in $objClusterResources)
{
#Get the associated disk
if($useCIM){
$objClusterDisks = (Get-CimAssociatedInstance -InputObject $objClusterResource -Association $WMI_CLUSTER_RESOURCE_TO_DISK_ASSOCIATOR_CLASS)
}else{
$objClusterDisks = $objClusterResource.GetRelated("MSCluster_Disk")
}
foreach ($objClusterDisk in $objClusterDisks)
{
#Get the associated disk partition
if($useCIM){
$objClusterDiskPartitions = (Get-CimAssociatedInstance -InputObject $objClusterDisk -Association $WMI_CLUSTER_DISKPARTITION_TO_DISK_ASSOCIATOR_CLASS)
}else{
$objClusterDiskPartitions = $objClusterDisk.GetRelated("MSCluster_DiskPartition")
}
foreach ($objClusterDiskPartition in $objClusterDiskPartitions)
{
$InstancesCount += 1
$list = CreateMonitoringData $objClusterDisk $objClusterDiskPartition $objClusterResource $strTargetComputer $strClusterName $objMomScriptAPI
}
}
}
$boolNoMonitoredClusterDiskAvailable.Value = ($InstancesCount -le 0)
}
else
{
$boolNoMonitoredClusterDiskAvailable.Value = $true
}
return $list
}

#****************************************************************************************************************
# 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
#****************************************************************************************************************
Function CreateMonitoringData($objClusterDisk, $objClusterDiskPartition, $objClusterResource,
$strTargetComputer, $strClusterName, $objMomScriptAPI) #As Boolean
{
$list = New-Object System.Collections.ArrayList($null)
#Create performance data
$strPartitionName = $objClusterResource.$WMI_NAME_PROPERTY_NAME + "_" + $objClusterDiskPartition.$WMI_PATH_PROPERTY_NAME

#Total Size /MB
$list.Add((CreatePerformanceTypedPropertyBag $PERF_OBJECT_CSV $PERF_COUNTER_TOTAL_SIZE_MB $strPartitionName `
$objClusterDiskPartition.$WMI_TOTALSIZE_PROPERTY_NAME $strPartitionName $objMomScriptAPI))

#Free Space /MB
$list.Add((CreatePerformanceTypedPropertyBag $PERF_OBJECT_CSV $PERF_COUNTER_FREE_SPACE_MB $strPartitionName `
$objClusterDiskPartition.$WMI_FREESPACE_PROPERTY_NAME $strPartitionName $objMomScriptAPI))

#Free Space /%
$list.Add((CreatePerformanceTypedPropertyBag $PERF_OBJECT_CSV $PERF_COUNTER_FREE_SPACE_PERCENT $strPartitionName `
([math]::Round(($objClusterDiskPartition.$WMI_FREESPACE_PROPERTY_NAME / $objClusterDiskPartition.$WMI_TOTALSIZE_PROPERTY_NAME), 2) * 100) $strPartitionName $objMomScriptAPI))

return $list
}

#***************************************************************************************
# 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
#***************************************************************************************
Function CreatePerformanceTypedPropertyBag($strObjectName, $strCounterName, $strInstanceName,
$varValue, $strCSVInstanceName, $objMomScriptAPI)
{

return @{ $PERFORMANCE_OBJECT_NAME = $strObjectName;
$PERFORMANCE_COUNTER_NAME = $strCounterName;
$PERFORMANCE_INSTANCE_NAME = $strInstanceName;
$PERFORMANCE_VALUE_NAME = $varValue;
$INSTANCE_NAME = $strCSVInstanceName}
}

Main
</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>mblnLogSuccessEvent</Name>
<Value>$Config/LogSuccessEvent$</Value>
</Parameter>
<Parameter>
<Name>mstrIdentifier</Name>
<Value>$Config/ScriptGroupId$</Value>
</Parameter>
<Parameter>
<Name>strTargetComputer</Name>
<Value>$Config/TargetComputer$</Value>
</Parameter>
<Parameter>
<Name>strClusterName</Name>
<Value>$Config/ClusterName$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</ProbeAction>
<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 ID="Scheduler"/>
</Node>
</Node>
</Node>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>SystemPerf!System.Performance.Data</OutputType>
</DataSourceModuleType>