S2D Faults WMI Alert Events Data Source

Microsoft.Windows.Server.10.0.Storage.StorageSpacesDirect.FaultWmiAlertEventDataSource (DataSourceModuleType)

Faults WMI alert events data source.

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityInternal
RunAsSystem.PrivilegedMonitoringAccount
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
WmiEventProviderDS DataSource Microsoft.Windows.WmiEventProvider Default
PA ProbeAction Microsoft.Windows.PowerShellPropertyBagProbe Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
PollIntervalint$Config/PollInterval$Polling Interval (sec)WMI event query polling interval.
TimeoutSecondsint$Config/TimeoutSeconds$Timeout (sec)
DebugModebool$Config/DebugMode$Enable debug outputEnable debug output

Source Code:

<DataSourceModuleType ID="Microsoft.Windows.Server.10.0.Storage.StorageSpacesDirect.FaultWmiAlertEventDataSource" Accessibility="Internal" RunAs="System!System.PrivilegedMonitoringAccount" Batching="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="InstanceType" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TargetInstanceUniqueID" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TargetInstanceObjectID" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ComputerName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="PollInterval" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="WQLQuery" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TargetId" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="TimeoutSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="0" name="VirtualDiskId" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="0" name="bagType" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="0" name="DebugMode" type="xsd:boolean"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="PollInterval" Selector="$Config/PollInterval$" ParameterType="int"/>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
<OverrideableParameter ID="DebugMode" Selector="$Config/DebugMode$" ParameterType="bool"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<DataSource ID="WmiEventProviderDS" TypeID="Windows!Microsoft.Windows.WmiEventProvider">
<NameSpace>\\$Config/ComputerName$\root\Microsoft\Windows\Storage</NameSpace>
<Query>$Config/WQLQuery$</Query>
<PollInterval>$Config/PollInterval$</PollInterval>
</DataSource>
<ProbeAction ID="PA" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagProbe">
<ScriptName>GetFaultsScript.ps1</ScriptName>
<ScriptBody><Script>

Param($TargetInstanceObjectID,$InstanceType, $SourceUniqueId, $SourceObjectId, $TargetId,$VirtualDiskId,$bagType)
$SCRIPT_NAME = "GetFaultsScript.ps1"


#general variables
#-----------------
$errorActionPreference = 'Stop'

$errEvent = [System.Diagnostics.EventLogEntryType]::Error;
$infoEvent = [System.Diagnostics.EventLogEntryType]::Information;
$GenericInformationEvent = 8671;
$GenericFailureEvent = 8672;
$DiscoveryGenericInformationEvent = 8861;
$DiscoveryGenericFailureEvent = 8862;
$script:traceMsg = "";
$ObjectNotFoundCode = -2146233087
$msft_namespace = "root\microsoft\windows\storage"
$cluster_namespace = "root\mscluster"

# Guid length for Virtual Disk
$guidLength = 38
$PadLength = 1 #Object Id ended with double quote


if ($false -eq [string]::IsNullOrEmpty($DebugMode))
{
$DebugMode = [string]::Equals("true",$DebugMode,[System.StringComparison]::OrdinalIgnoreCase)
}
else
{
$DebugMode = $false
}

$momAPI = New-Object -comObject 'MOM.ScriptAPI'

#Common Functions
Function Get-Guid([string]$sguid)
{
if ([string]::IsNullOrEmpty($sguid))
{
return $null
}

$guid = [guid]::NewGuid()
if ($false -eq [guid]::TryParse($sguid,[ref] $guid))
{
return $null;
}

return $guid
}

Function GetDiskIdFilterFromVdObjectId([string]$ObjectId)
{
if ($true -eq [string]::IsNullOrEmpty($ObjectId))
{
return $null
}

$Length = $ObjectId.Length
#check guid length - 38 in {guid} format
$rGuidLength = $guidLength + $PadLength
if ($Length -lt $rGuidLength) {return $null;}

$sguid = $ObjectId.Substring($Length - $rGuidLength,$guidLength)

$guid = Get-Guid -sguid $sguid

if ($null -eq $guid) {return $null;}

return "DiskId='\\\\?\\Disk{$guid}'"
}

Function GetVolumesFromVd($vd)
{
$errorActionPreference = "Stop"

$Filter = GetDiskIdFilterFromVdObjectId -ObjectId $vd.ObjectId
if ($null -eq $Filter ) {return $null;}

$partitions = Get-CimInstance -ClassName "MSFT_Partition" -Namespace $msft_namespace -Filter $Filter | Where-Object {$_.AccessPaths -ne $null}
$volumes = @{}

foreach ($partition in $partitions)
{
$Volume = Get-CimAssociatedInstance -Association "MSFT_PartitionToVolume" -InputObject $partition -Namespace $msft_namespace
if ($null -ne $Volume -and "CSVFS" -eq $Volume.FileSystem )
{
$volumes[$Volume] = 1;
}
}

return $volumes
}

Function AddTraceMessage
{
param($message)

$errorActionPreference = 'SilentlyContinue'
$timeStamp = (get-date -format "HH:mm:ss:fff");
$script:traceMsg = $script:traceMsg + "`n[" + $timeStamp + "] " + $message;
}

Function Log-FinalDebugData([int]$FailureEvent,[int]$InformationEvent,$exception,[string]$SCRIPT_NAME,[string]$traceMsg,[bool]$DebugMode = $false,$message = [string]::Empty)
{
$ErrorActionPreference = "SilentlyContinue"

if ($null -ne $exception)
{
if ([string]::Empty -eq $message) {$message = "Error occured during script execution:"}
$momAPI.LogScriptEvent($SCRIPT_NAME, $FailureEvent, 1, "$message $($exception.Message)");
}

if ($script:traceMsg -ne $null -and $true -eq $DebugMode)
{
$momAPI.LogScriptEvent($SCRIPT_NAME,$InformationEvent, 0, $traceMsg);
}
}

Function Check-CimError($Exception)
{
$errorActionPreference = 'SilentlyContinue'
$result = $false

if ($null -eq $Exception)
{
return $result
}

$error.Clear()
$type = $Exception.GetType()

if (0 -ne $error.Count)
{
$error.Clear()
return $result
}

if ("Microsoft.PowerShell.Cmdletization.Cim.CimJobException" -eq $type.FullName -and $ObjectNotFoundCode -eq $Exception.HResult)
{
$result = $true
}

return $result
}

Function Get-FaultException($exception,$IsObjectExist)
{
if ($false -eq $IsObjectExist)
{
$IsError = Check-CimError -Exception $exception
if ($true -eq $IsError)
{
$exception = $null
}

}

return $exception

}

Function Load-Module ([string] $ModuleName)
{
if ([string]::IsNullOrEmpty($ModuleName) )
{
return $false
}

$ErrorActionPreference="SilentlyContinue"
$error.Clear()

$retval = $false
$Tmodule = Get-Module -Name $ModuleName

########Check for powershell 1.0
if ($error.Count -ne 0)
{
$Exception = $error[0].Exception

if ($null -ne $Exception)
{
$type = $Exception.GetType()
if ([System.Management.Automation.CommandNotFoundException] -eq $type)
{
$error.Clear()
return $retval
}
}

$error.Clear()
}

if ($null -eq $Tmodule)
{
$Tmodule = Get-Module -Name $ModuleName -ListAvailable
if ($error.Count -ne 0){ return $retval;}
if ($null -eq $Tmodule) {return $retval;}

Import-Module $ModuleName
if ($error.Count -eq 0){ $retval = $true;}

}
else
{
$retval = $true
}

return $retval

}

AddTraceMessage -message "Start on Node: $env:COMPUTERNAME"
$IsStorageModuleReady = Load-Module -ModuleName "Storage"

if ($false -eq $IsStorageModuleReady)
{
if ($error.Count -ne 0)
{
$message = "Cannot initializa Storage module. Error: " + $error[0].ToString()

}
else
{
$message = "Cannot load Storage module."
}

AddTraceMessage -message $message

}

#Load cimcmdlets
$IsCimReady = Load-Module -ModuleName "CimCmdLets"







$ITEM_DATA_TYPE = "Item"
$LIST_DATA_TYPE = "List"
$Fail_DATA_TYPE = "fLst"


Function Add-PropertyBag($fault,$SourceUniqueId,$SourceObjectId,$TargetId,[HashTable]$faultIdTbl)
{
$errorActionPreference = 'Stop'

$faultId = $fault.FaultId;
$alertSeverity = 1;

$alertSevString = "$($fault.PerceivedSeverity)"

if($fault.PerceivedSeverity -eq "2" -or $fault.PerceivedSeverity -eq "Information")
{
$alertSeverity = 0 #Information
}
elseif(($fault.PerceivedSeverity -eq "3") -or ($fault.PerceivedSeverity -eq "4") -or ( "Minor" -eq $fault.PerceivedSeverity) -or ("Degraded/Warning" -eq $fault.PerceivedSeverity))
{
$alertSeverity = 1 #Warning
}
elseif(($fault.PerceivedSeverity -ge "5"))
{
$alertSeverity = 2 #Error
}
elseif(("Major" -eq $fault.PerceivedSeverity) -or ("Critical" -eq $fault.PerceivedSeverity ) -or ("Fatal/NonRecoverable" -eq $fault.PerceivedSeverity))
{
$alertSeverity = 2 #Error
}

$propertyBag = $momAPI.CreatePropertyBag()
$propertyBag.AddValue("FaultId", $faultId);
$propertyBag.AddValue("FaultingObjectDescription", $fault.FaultingObjectDescription);
$propertyBag.AddValue("FaultingObjectLocation", $fault.FaultingObjectLocation);
$propertyBag.AddValue("Reason", $fault.Reason);
$propertyBag.AddValue("RecommendedActions", $fault.RecommendedActions -join "`n");
$propertyBag.AddValue("CompositeAlertId", $faultId + ":" + $SourceObjectId);
$propertyBag.AddValue("SourceUniqueId", $SourceUniqueId);
$propertyBag.AddValue("SourceObjectId", $SourceObjectId);
$propertyBag.AddValue("TargetId", $TargetId);
$propertyBag.AddValue("DataType", $ITEM_DATA_TYPE); #required in condition detection for generate/close alerts
$propertyBag.AddValue("Severity", $alertSeverity);

#Publish property bag data
$propertyBag

if ($false -eq [string]::IsNullOrEmpty($faultId))
{
$faultIdTbl[$faultId] = 1
}
}

Function ProcessFaultsByBag($faults,$SourceUniqueId,$SourceObjectId,$TargetId,[HashTable]$faultIdTbl)
{
$errorActionPreference = 'Stop'

if ($null -eq $faults) {return;}

foreach($fault in $faults)
{
Add-PropertyBag -fault $fault -SourceUniqueId $SourceUniqueId -SourceObjectId $SourceObjectId -TargetId $TargetId -faultIdTbl $faultIdTbl

}
}

function Print-TraceData()
{
$errorActionPreference = "SilentlyContinue"
AddTraceMessage -message "Storage monitoring script $SCRIPT_NAME started."
AddTraceMessage -message "InstanceType = $InstanceType."
AddTraceMessage -message "SourceUniqueId = $SourceUniqueId."
AddTraceMessage -message "TargetId = $TargetId."
AddTraceMessage -message "TargetInstanceObjectID=$TargetInstanceObjectID"
AddTraceMessage -message "SourceObjectId=$SourceObjectId"

$error.Clear()
}







#Param($TargetInstanceObjectID,$InstanceType, $SourceUniqueId, $SourceObjectId, $TargetId,$VirtualDiskId,$DebugMode)


Function Get-VirtualDiskById($UniqueID)
{
$ErrorActionPreference = 'Stop'
$vd = $null

try
{
$vd = Get-VirtualDisk -UniqueID $UniqueID
}
catch
{
$exception = Get-FaultException -exception $_.Exception -IsObjectExist $false
if ($null -ne $exception)
{
Throw $exception
}
}

return $vd
}

Function Get-VolumeById($UniqueID)
{
$ErrorActionPreference = 'Stop'

$IsWmiError = $False;
$Volumes = $null

try
{
$Volumes = Get-Volume -UniqueID $UniqueID
}
catch
{
$exception = Get-FaultException -exception $_.Exception -IsObjectExist $false
if ($null -ne $exception)
{
$IsWmiError = $true
Throw $exception
}
}
finally
{
#Check if virtual disk is offline
#In this case generate exception and don't generate new faults and close old volume faults
if ($null -eq $Volumes -and $false -eq $IsWmiError)
{
$vd = Get-VirtualDiskById -UniqueID $VirtualDiskId
if ($null -ne $vd -and "OK" -ne $vd.OperationalStatus )
{
$ex = New-Object -TypeName "System.NotSupportedException" -ArgumentList ("Virtual Disk is not in operational state.")
Throw $ex
}
}
}

return $volumes

}

Function Get-FauiltsByObjectId([string]$Id,[string]$instanceType,[ref]$storageObjectsCount)
{
$ErrorActionPreference = 'Stop'

$objects = $null
$ex = $null
$result = $null
$IsExist = $false

try
{
if ("SSS" -eq $instanceType)
{
$objects = Get-StorageSubSystem -UniqueID $Id
$IsExist = $true
if ($null -ne $objects)
{
$result = $objects | Debug-StorageSubSystem
}
}
elseif("V" -eq $instanceType)
{
$objects = Get-VolumeById -UniqueID $Id
$IsExist = $true
if ($null -ne $objects)
{
$result = $objects | Debug-Volume
}
}
elseif("FS" -eq $instanceType)
{
$objects = Get-FileShare -UniqueID $Id
$IsExist = $true
if ($null -ne $objects)
{
$result = $objects | Debug-FileShare
}
}
else
{
$ex = New-Object -TypeName "System.NotSupportedException" -ArgumentList ("Type of storage instance is not supported")
Throw $ex
}
}
catch
{
$exception = Get-FaultException -exception $_.Exception -IsObjectExist $IsExist

if ($null -ne $exception)
{
Throw $exception
}
}

if ($null -eq $objects)
{
return $null
}
else
{
$oCount = $objects.Count
if ($null -eq $oCount){$oCount = 1;}
if ($null -ne $storageObjectsCount)
{
$storageObjectsCount.Value = $oCount
}
}


if ($null -ne $result)
{
$result = @($result)
}

return $result
}

Function Get-Faults
{
param($instanceType, $UniqueID,[ref]$storageObjectsCount)
$errorActionPreference = 'Stop'
$error.Clear()

$result = $null

if ([string]::IsNullOrEmpty($UniqueID))
{

Throw [System.ArgumentException] "Get-Faults: Cannot validate argument on parameter 'UniqueId'. The argument is empty."
}

if ([string]::IsNullOrEmpty($UniqueID.Trim()))
{
Throw [System.ArgumentException] "Get-Faults: Cannot validate argument on parameter 'UniqueId'. The argument is empty."
}

$objectsCount = 0
$result = (Get-FauiltsByObjectId -Id $UniqueID -instanceType $instanceType -storageObjectsCount ([ref]$objectsCount))
if ($null -ne $storageObjectsCount){$storageObjectsCount.Value = $objectsCount;}

return $result
}

function Add-ResultFaults([string]$faultIds,$IsError)
{
$errorActionPreference = 'Stop'

$ItemType = $LIST_DATA_TYPE
##########################################################
# If Error occuried donn't return any data to close alert
##########################################################
if ($true -eq $IsError)
{
AddTraceMessage -message "Error occuried during faults proccessing. Don't return faults list to close."
return
}

AddTraceMessage -message "joined id list [$faultIds]"

try
{
$listPropertyBag = $momAPI.CreatePropertyBag()

$listPropertyBag.AddValue("FaultId", $faultIds);
$listPropertyBag.AddValue("SourceUniqueId", $SourceUniqueId);
$listPropertyBag.AddValue("SourceObjectId", $SourceObjectId);
$listPropertyBag.AddValue("TargetId", $TargetId);
$listPropertyBag.AddValue("DataType", $ItemType);

$listPropertyBag

AddTraceMessage -message "Final propertyBag was added. "

}
catch [System.Exception]
{
AddTraceMessage -message "Cannot create final Fault list property Bag. "
AddTraceMessage -message $_.Exception.Message
}


}

function Start-FinalAction($IsError,$IsFaultReturn,$IsAddingDataComplete,$Exception,[string]$faultIds)
{
$errorActionPreference = 'SilentlyContinue'

if ($false -eq $IsFaultReturn)
{
AddTraceMessage -message "Cannot get faults data."
}
else
{
if($false -eq $IsAddingDataComplete)
{
AddTraceMessage -message "Not all faults have been processed successfully"
}
}


Add-ResultFaults -faultIds $faultIds -IsError $IsError

Log-FinalDebugData -FailureEvent $GenericFailureEvent -InformationEvent $GenericInformationEvent -exception $exception -SCRIPT_NAME $SCRIPT_NAME -traceMsg $script:traceMsg -DebugMode $DebugMode

}

Function ProcessData($faults,[ref]$faultIds)
{
$errorActionPreference = "Stop"

$faultIdString = [string]::Empty

if ($null -eq $faults)
{
return
}

$faultIdHash = @{}

ProcessFaultsByBag -faults $faults -SourceUniqueId $SourceUniqueId -SourceObjectId $SourceObjectId -TargetId $TargetId -faultIdTbl $faultIdHash

if (0 -ne $faultIdHash.Count)
{
$faultIdString = [string]::Join(",",@($faultIdHash.Keys))

}

if($faultIds -ne $null)
{
$faultIds.Value = $faultIdString
}

$faultCount = $faults.Count
if ($null -eq $faultCount)
{
$faultCount = 1
}

AddTraceMessage -message "Get Faults: $($faultCount) fault(s) has been proccessed."

}

function Main()
{
$errorActionPreference = "Stop"

$IsError = $false
$IsFaultReturn = $false
$IsAddingDataComplete = $false
$faultIds = [string]::Empty
$storageObjectsCount = 0


Print-TraceData

if ($TargetInstanceObjectID -ne $SourceObjectId)
{
AddTraceMessage -message "Faults were not found for this target : $TargetInstanceObjectID"
Start-FinalAction -IsError $true -IsFaultReturn $IsFaultReturn -IsAddingDataComplete $IsAddingDataComplete -Exception $null -faultIds $faultIds

return
}

if ($false -eq $IsStorageModuleReady)
{
$momAPI.LogScriptEvent($scriptName, $GenericFailureEvent, 1, $script:traceMsg);
Start-FinalAction -IsError $true -IsFaultReturn $IsFaultReturn -IsAddingDataComplete $IsAddingDataComplete -Exception $null -faultIds $faultIds
return
}


try
{
$faults = Get-Faults -instanceType $InstanceType -UniqueID $SourceUniqueId -storageObjectsCount ([ref] $storageObjectsCount)
$IsFaultReturn = $true

if($null -eq $faults)
{
if (0 -eq $storageObjectsCount)
{
AddTraceMessage -message "Storage object with Id:[$SourceUniqueId] was not found"
}
else
{
AddTraceMessage -message "Faults were not found."
}
}
else
{
if (0 -eq $faults.Count)
{
AddTraceMessage -message "faults were not found"
}

ProcessData -faults $faults -faultIds ([ref] $faultIds)
}

$IsAddingDataComplete = $true
}
catch
{
##################################################
# There are the following reason of exception
# 1. From Get-Faults. If and only if:
# 1.1 Bad SourceUniqueId (null or contains only spaces)
# 1.2 Exception during Get-Storage.. cmdlets
# 1.3 Exception during Debug Cmdlets
# 2. Exception in Add-propertyBag (Maybe incomplete fault data)
#
#
##################################################
$IsError = $true
$Exception = $_.Exception
AddTraceMessage -message $Exception.Message
}
finally
{
Start-FinalAction -IsError $IsError -IsFaultReturn $IsFaultReturn -IsAddingDataComplete $IsAddingDataComplete -Exception $Exception -faultIds $faultIds
}


}


Main

</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>TargetInstanceObjectID</Name>
<Value>$Config/TargetInstanceObjectID$</Value>
</Parameter>
<Parameter>
<Name>InstanceType</Name>
<Value>$Config/InstanceType$</Value>
</Parameter>
<Parameter>
<Name>SourceUniqueId</Name>
<Value>$Config/TargetInstanceUniqueID$</Value>
</Parameter>
<Parameter>
<Name>SourceObjectId</Name>
<Value>$Data/Property[@Name='SourceObjectId']$</Value>
</Parameter>
<Parameter>
<Name>TargetId</Name>
<Value>$Config/TargetId$</Value>
</Parameter>
<Parameter>
<Name>VirtualDiskId</Name>
<Value>$Config/VirtualDiskId$</Value>
</Parameter>
<Parameter>
<Name>bagType</Name>
<Value>$Config/bagType$</Value>
</Parameter>
<Parameter>
<Name>DebugMode</Name>
<Value>$Config/DebugMode$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
<StrictErrorHandling>true</StrictErrorHandling>
</ProbeAction>
<!--<ConditionDetection ID="CD" TypeID="System!System.ExpressionFilter">
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="String">Property[@Name='SourceUniqueId']</XPathQuery>
</ValueExpression>
<Operator>Equal</Operator>
<ValueExpression>
<Value>$Config/TargetInstanceUniqueID$</Value>
</ValueExpression>
</SimpleExpression>
</Expression>
</ConditionDetection>-->
</MemberModules>
<Composition>
<!--<Node ID="CD">-->
<Node ID="PA">
<Node ID="WmiEventProviderDS"/>
</Node>
<!--</Node>-->
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
</DataSourceModuleType>