Storage Instance filtered Object Health On-demand Detection Probe Action

Microsoft.Windows.Server.10.0.Storage.StorageSpacesDirect.StorageObjectHealthStateProbe.InstanceFilter (ProbeActionModuleType)

Probe action type used to trigger storage object health status query during monitor initialization and on-demand detection.

Element properties:

TypeProbeActionModuleType
IsolationAny
AccessibilityPublic
RunAsDefault
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
PassThrough ProbeAction System.PassThroughProbe Default
Script ProbeAction Microsoft.Windows.PowerShellPropertyBagProbe Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
TimeoutSecondsint$Config/TimeoutSeconds$Timeout (sec)

Source Code:

<ProbeActionModuleType ID="Microsoft.Windows.Server.10.0.Storage.StorageSpacesDirect.StorageObjectHealthStateProbe.InstanceFilter" Accessibility="Public" Batching="false" PassThrough="false">
<Configuration>
<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="StorageClassName" 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" minOccurs="1" maxOccurs="1" name="TimeoutSeconds" type="xsd:integer"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<ProbeAction ID="PassThrough" TypeID="System!System.PassThroughProbe"/>
<ProbeAction ID="Script" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagProbe">
<ScriptName>StorageObjectHealthStateProbeScriptFilter.ps1</ScriptName>
<ScriptBody><Script>

param([string] $targetInstanceUniqueID, [string] $targetInstanceObjectID, [string] $storageClassName)



#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"





#param([string] $targetInstanceUniqueID, [string] $targetInstanceObjectID, [string] $storageClassName)


$scriptName = "StorageObjectHealthStateProbeScript.ps1"
#Create Storage CurrentHealthStatus property bag data
$propertyBag = $momAPI.CreatePropertyBag()

$PropertyBagProperty_CurrentHealthStatus = "CurrentHealthStatus"

# MSFT_StorageObject HealthStatus values
$MSFT_StorageObject_HealthStatus_HEALTHY = "Healthy"
$MSFT_StorageObject_HealthStatus_WARNING = "Warning"
$MSFT_StorageObject_HealthStatus_UNHEALTHY = "Unhealthy"

# StorageFaultEvent CurrentHealthStatusValues; that maps to MSFT_StorageObject HealthStatus values
$CurrentHealthStatus_HEALTHY = 0
$CurrentHealthStatus_WARNING = 1
$CurrentHealthStatus_UNHEALTHY = 2

# Property Bag property value
$currentHealthStatus = 0; #default health status

$IsStorageObjectExist = $false

if ($false -eq $IsStorageModuleReady)
{
$momAPI.LogScriptEvent($scriptName, $GenericFailureEvent, 1, $script:traceMsg);
exit
}

Try
{
$error.Clear();

AddTraceMessage -message -join ("Storage monitoring script ", $scriptName," started.")

AddTraceMessage -message "Storage class = $storageClassName `nstorage unique id = $targetInstanceUniqueID `nobject id = $targetInstanceObjectID"

$propertyBag.AddValue("SourceUniqueId", $targetInstanceUniqueID);
$propertyBag.AddValue("SourceObjectId", $targetInstanceObjectID);
$storageObject = $null
AddTraceMessage -message "Start finding the object."
if($storageClassName -eq "MSFT_StorageSubSystem")
{
$storageObject = Get-StorageSubsystem -UniqueId $targetInstanceUniqueID
$IsStorageObjectExist = $true
#$storageObject = Get-StorageSubsystem -ObjectId $targetInstanceObjectID
}
elseif($storageClassName -eq "MSFT_Volume")
{
$storageObject = Get-Volume -UniqueId $targetInstanceUniqueID
$IsStorageObjectExist = $true
#$storageObject = Get-StorageSubsystem -ObjectId $targetInstanceObjectID
}
elseif($storageClassName -eq "MSFT_FileShare")
{
$storageObject = Get-FileShare -UniqueId $targetInstanceUniqueID
$IsStorageObjectExist = $true
#$storageObject = Get-StorageSubsystem -ObjectId $targetInstanceObjectID
}
elseif($storageClassName -eq "MSFT_StoragePool")
{
$storageObject = Get-StoragePool -UniqueId $targetInstanceUniqueID
$IsStorageObjectExist = $true

if($storageObject.OperationalStatus -eq "OK")
{
$currentHealthStatus = $CurrentHealthStatus_HEALTHY; # i.e. 0
}
elseif($storageObject.OperationalStatus -eq "Degraded")
{
$currentHealthStatus = $CurrentHealthStatus_WARNING; # i.e. 1
}
elseif($storageObject.OperationalStatus -eq "Read-only")
{
$currentHealthStatus = $CurrentHealthStatus_UNHEALTHY; # i.e. 2
}

AddTraceMessage -message "HealthStatus of storage object = $hs`n CurrentHealthStatus property bag value = $currentHealthStatus"
$propertyBag.AddValue("CurrentHealthStatus", $currentHealthStatus);
$propertyBag.AddValue("OperationalStatus", $storageObject.OperationalStatus);
$propertyBag
return

}
elseif($storageClassName -eq "MSFT_StorageNode")
{
$storageObject = Get-StorageNode -UniqueId $targetInstanceUniqueID
$IsStorageNodeExist = $true

if($storageObject.OperationalStatus -eq "UP")
{
$currentHealthStatus = $CurrentHealthStatus_HEALTHY; # i.e. 0
}
elseif($storageObject.OperationalStatus -eq "Unknown")
{
$currentHealthStatus = $CurrentHealthStatus_UNHEALTHY; # i.e. 2
}
elseif($storageObject.OperationalStatus -eq "Joining")
{
$currentHealthStatus = $CurrentHealthStatus_WARNING; # i.e. 1
}
elseif($storageObject.OperationalStatus -eq "Paused")
{
$currentHealthStatus = $CurrentHealthStatus_WARNING; # i.e. 1
}
elseif($storageObject.OperationalStatus -eq "Down")
{
$currentHealthStatus = $CurrentHealthStatus_UNHEALTHY; # i.e. 2
}

$hs = ($storageObject.OperationalStatus);

AddTraceMessage -message "HealthStatus of storage object = $hs`n CurrentHealthStatus property bag value = $currentHealthStatus"

$propertyBag.AddValue("CurrentHealthStatus", $currentHealthStatus);
$propertyBag.AddValue("OperationalStatus", $storageObject.OperationalStatus);

$propertyBag

return
}
elseif($storageClassName -eq "MSFT_PhysicalDisk")
{
$storageObject = Get-PhysicalDisk -UniqueId $targetInstanceUniqueID
$IsStorageNodeExist = $true

if($storageObject.HealthStatus -eq "Healthy")
{
$currentHealthStatus = $CurrentHealthStatus_HEALTHY; # i.e. 0
}
elseif($storageObject.HealthStatus -eq "Warning")
{
$currentHealthStatus = $CurrentHealthStatus_WARNING; # i.e. 1
}
elseif($storageObject.HealthStatus -eq "Unhealthy")
{
$currentHealthStatus = $CurrentHealthStatus_UNHEALTHY; # i.e. 2
}
elseif($storageObject.HealthStatus -eq "Unknown")
{
$currentHealthStatus = $CurrentHealthStatus_UNHEALTHY; # i.e. 2
}

$hs = ($storageObject.OperationalStatus);

AddTraceMessage -message "HealthStatus of storage object = $hs`n CurrentHealthStatus property bag value = $currentHealthStatus"

$propertyBag.AddValue("CurrentHealthStatus", $currentHealthStatus);
$propertyBag.AddValue("OperationalStatus", $storageObject.OperationalStatus);
$propertyBag.AddValue("HealthStatus", $storageObject.HealthStatus);

$propertyBag

return
}

if ($storageObject -eq $null)
{
#Throw [System.NullReferenceException] -join("Can't find Storage Object with UniqueID = ", $targetInstanceUniqueID);
#Throw [System.NullReferenceException] -join("Can't find Storage Object with ObjectID = ", $targetInstanceObjectID);
exit
}

if($storageObject.HealthStatus -eq $MSFT_StorageObject_HealthStatus_HEALTHY)
{
$currentHealthStatus = $CurrentHealthStatus_HEALTHY; # i.e. 0
}
elseif($storageObject.HealthStatus -eq $MSFT_StorageObject_HealthStatus_WARNING)
{
$currentHealthStatus = $CurrentHealthStatus_WARNING; # i.e. 1
}
elseif($storageObject.HealthStatus -eq $MSFT_StorageObject_HealthStatus_UNHEALTHY)
{
$currentHealthStatus = $CurrentHealthStatus_UNHEALTHY; # i.e. 2
}

$hs = ($storageObject.HealthStatus);

AddTraceMessage -message "HealthStatus of storage object = $hs`n CurrentHealthStatus property bag value = $currentHealthStatus"

$propertyBag.AddValue("CurrentHealthStatus", $currentHealthStatus);

$propertyBag

AddTraceMessage -message -join ("Storage monitoring script ", $scriptName, " completed.");
}
Catch
{
AddTraceMessage -message $_.Exception.Message
$exception = Get-FaultException -exception $_.Exception -IsObjectExist $IsStorageObjectExist
}
Finally
{
if ($null -ne $exception)
{
$momAPI.LogScriptEvent($scriptName, $GenericFailureEvent, 1, $exception.Message);
}

if ($script:traceMsg -ne $null)
{
#Debug
AddTraceMessage -message "ImortResult = $importLog"
$momAPI.LogScriptEvent($scriptName, $GenericInformationEvent, 0, $script:traceMsg);
}
}</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>targetInstanceUniqueID</Name>
<Value>$Config/TargetInstanceUniqueID$</Value>
</Parameter>
<Parameter>
<Name>targetInstanceObjectID</Name>
<Value>$Config/TargetInstanceObjectID$</Value>
</Parameter>
<Parameter>
<Name>storageClassName</Name>
<Value>$Config/StorageClassName$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
<StrictErrorHandling>true</StrictErrorHandling>
</ProbeAction>
</MemberModules>
<Composition>
<Node ID="Script">
<Node ID="PassThrough"/>
</Node>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
<TriggerOnly>true</TriggerOnly>
</ProbeActionModuleType>