Microsoft Windows Server Storage Storage Spaces Direct Close Alerts Write Action
Microsoft.Windows.Server.10.0.Storage.StorageSpacesDirect.CloseAlertsWriteAction (WriteActionModuleType)
Storage Spaces Direct close alerts write action.
Element properties: Member Modules:
Overrideable Parameters:
Source Code: <WriteActionModuleType ID="Microsoft.Windows.Server.10.0.Storage.StorageSpacesDirect.CloseAlertsWriteAction" Accessibility="Internal" Batching="true" RunAs="System!System.PrivilegedMonitoringAccount">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="FaultId" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="StorageUniqueID" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="StorageObjectID" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="TargetId" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="DataType" 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="RuleId1" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="0" name="RuleId2" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="0" name="RuleId3" type="xsd:string"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<ConditionDetection ID="CD" TypeID="System!System.ExpressionFilter">
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="String">Property[@Name='DataType']</XPathQuery>
</ValueExpression>
<Operator>Equal</Operator>
<ValueExpression>
<Value Type="String">List</Value>
</ValueExpression>
</SimpleExpression>
</Expression>
</ConditionDetection>
<WriteAction ID="WA" TypeID="Windows!Microsoft.Windows.PowerShellWriteAction">
<ScriptName>CloseAlerts.ps1</ScriptName>
<ScriptBody><Script>
param($faultIds, $storageObjectUniqueID, $storageObjectObjectID, $targetId,$EventType,$RuleId1,$RuleId2,$RuleId3)
$SCRIPT_NAME = "CloseAlerts.ps1"
#general variables
#-----------------
$errorActionPreference = 'Stop'
$errEvent = [System.Diagnostics.EventLogEntryType]::Error;
$infoEvent = [System.Diagnostics.EventLogEntryType]::Information;
$GenericInformationEvent = 8671;
$GenericFailureEvent = 8672;
$script:traceMsg = "";
$momAPI = New-Object -comObject 'MOM.ScriptAPI'
$ResolutionStateClose = 255;
$ResolutionStateActive = 0;
$AlertCriteria = "IsMonitorAlert = 'false' and ResolutionState = $ResolutionStateActive and CustomField1 = 'Fault' "
if ($false -eq [string]::IsNullOrEmpty($DebugMode))
{
$DebugMode = [string]::Equals("true",$DebugMode,[System.StringComparison]::OrdinalIgnoreCase)
}
else
{
$DebugMode = $false
}
Function AddTraceMessage
{
param($message)
$errorActionPreference = 'SilentlyContinue'
$timeStamp = (get-date -format "HH:mm:ss:fff");
$script:traceMsg = $script:traceMsg + "`n[" + $timeStamp + "] " + $message;
}
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 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 Prepare-ScomConnection()
{
$ErrorActionPreference = "Stop"
$managementServerName = "localhost"
$result = $true
try
{
#Import-Module OperationsManager
$omModule = get-module -name "OperationsManager"
if ($omModule -eq $null)
{
$SCOMPowerShellKey = "HKLM:\SOFTWARE\Microsoft\System Center Operations Manager\12\Setup\Powershell\V2"
$SCOMModulePath = Join-Path (Get-ItemProperty $SCOMPowerShellKey).InstallDirectory "OperationsManager"
[void](Import-module $SCOMModulePath)
}
AddTraceMessage -message "Connecting to $managementServerName OM management server."
New-SCManagementGroupConnection -ComputerName $managementServerName
AddTraceMessage -message "Connected to $managementServerName SDK. Now getting target class Instance"
}
catch
{
$result = $false
}
return $result
}
AddTraceMessage -message "Start on Management Server: $env:COMPUTERNAME"
#param($faultIds, $storageObjectUniqueID, $storageObjectObjectID, $targetId,$EventType,$RuleId1,$RuleId2,$RuleId3)
#ruleId1 - Generate Alert Rule
#ruleId2 - Refresh Alert Rule
#ruleId3 - Sync Alert Rule
$AlertRules = @(1..3)
Function ParseFaultIds
{
param([string]$inpt)
$result = @{}
if($true -eq [string]::IsNullOrEmpty($inpt))
{
return $result;
}
$separator = ","
$option = [System.StringSplitOptions]::RemoveEmptyEntries
$faults = $inpt.Split($separator, $option)
foreach($fault in $faults)
{
$faultId = Get-Guid -sguid $fault
if ($null -ne $faultId)
{
$result[$faultId] = 1
}
}
return $result
}
Function CloseAlerts
{
param($alerts)
$ErrorActionPreference = "Stop"
$alertsCount = $alerts.Count
if ($null -eq $alerts -or 0 -eq $alertsCount) {return}
Try
{
AddTraceMessage -message "Trying to close $alertsCount Alert(s)."
foreach($alert in $alerts)
{
$alert.ResolutionState = $ResolutionStateClose
if ($null -eq $alert.ManagementGroup.IsConnected) {continue;}
if ($false -eq $alert.ManagementGroup.IsConnected) {$alert.ManagementGroup.Reconnect();}
$alert.Update("Closed by S2D sync rule");
}
AddTraceMessage -message "All $alertsCount Alert(s) are closed."
}
Catch
{
AddTraceMessage -message $_.Exception.Message
}
}
Function Get-AlertRuleCriteria()
{
$ErrorActionPreference = "Stop"
$result = $AlertCriteria
$rules = @()
$rule1 = Get-Guid -sguid $RuleId1
$rule2 = Get-Guid -sguid $RuleId2
$rule3 = Get-Guid -sguid $RuleId3
if ($null -ne $rule1)
{$rule = "MonitoringRuleId='{0}'" -f $rule1 ; $rules += $rule; $AlertRules[0] = $rule1;}
else
{
$AlertRules[0] = $null
}
if ($null -ne $rule2)
{$rule = "MonitoringRuleId='{0}'" -f $rule2 ; $rules += $rule; $AlertRules[1] = $rule2;}
else
{
$AlertRules[1] = $null
}
if ($null -ne $rule3)
{$rule = "MonitoringRuleId='{0}'" -f $rule3 ; $rules += $rule; $AlertRules[2] = $rule3}
else
{
$AlertRules[2] = $null
}
if (0 -ne $rules.Length)
{
$result = "(" + ($rules -join " or " ) + ") and " + $result
}
$MonAlertCriteria = New-Object -TypeName "Microsoft.EnterpriseManagement.Monitoring.MonitoringAlertCriteria" -ArgumentList ($result)
return $MonAlertCriteria
}
Function Get-AlertsFromObject($mo,$criteria)
{
$ErrorActionPreference = "Stop"
if ($null -eq $mo -or $null -eq $criteria)
{
return $null
}
$mg = $mo.ManagementGroup
If ($null -eq $mg) {return $null;}
if ($false -eq $mg.IsConnected)
{
$mg.ReConnect()
}
return $mo.GetMonitoringAlerts($criteria)
}
Function Get-ActiveAlertForNonRule1($alerts)
{
#FaultId from Rule1
$RuleAlerts = @{}
$Rule2 = $AlertRules[1]
$Rule3 = $AlertRules[2]
if ($null -eq $Rule2 -and $null -eq $Rule3)
{
return $null
}
if ($null -eq $Rule2)
{
$newAlerts = $alerts | Where-Object { $_.RuleId -eq $Rule3}
}
else
{
if ($null -eq $Rule3)
{
$newAlerts = $alerts | Where-Object { $_.RuleId -eq $Rule2}
}
else
{
$newAlerts = $alerts | Where-Object { $_.RuleId -eq $Rule2 -or $_.RuleId -eq $Rule3}
}
}
return $newAlerts
}
Function Get-ActiveAlertForRule1($alerts)
{
#FaultId from Rule1
$RuleAlerts = @{}
$RuleId = $AlertRules[0]
if ($null -eq $alerts -or $null -eq $RuleId)
{
return $RuleAlerts
}
$Ralerts = $alerts | Where-Object { $_.RuleId -eq $RuleId}
if ($null -eq $Ralerts)
{
return $RuleAlerts
}
foreach($alert in $Ralerts)
{
$faultId = Get-FaultIdFromAlert -alert $alert
if ($null -eq $faultId) {continue;}
$RuleAlerts[$faultId] = 1
}
return $RuleAlerts
}
Function Get-DuplicateAlertsForClose($alerts)
{
if ($null -eq $alerts )
{
return $null
}
$alertsNonRule1 = Get-ActiveAlertForNonRule1 -alerts $alerts
#If null - nothing to close
if ($null -eq $alertsNonRule1) {return $null;}
$Rule1Faults = Get-ActiveAlertForRule1 -alerts $alerts
#If null - nothing to close
if ($null -eq $Rule1Faults -or 0 -eq $Rule1Faults.Count) {return $null;}
$newAlerts = @{}
foreach($alert in $alertsNonRule1)
{
$faultId = Get-FaultIdFromAlert -alert $alert
if ($null -eq $faultId) {continue;}
if ($true -eq $Rule1Faults.ContainsKey($faultId)) { $newAlerts[$alert] = 1;}
}
if (0 -eq $newAlerts.Count) {$newAlerts = $null;}
return $newAlerts;
}
Function Get-FaultIdFromAlert($alert)
{
$ErrorActionPreference = "SilentlyContinue"
if ($null -eq $alert)
{
return $null
}
$faultId = Get-Guid -sguid $alert.CustomField2
if ($null -ne $faultId) {return $faultId}
$error.Clear()
$context = [xml]$alert.Context
if (0 -ne $error.Count -or $null -eq $context)
{
$error.Clear()
return $null
}
$faultId = Get-Guid -sguid $context.SelectSingleNode("/DataItem/Property[@Name='FaultId']").InnerText
return $faultId
}
Function Get-ActiveAlerts($storageObjectId,[HashTable]$activefaults)
{
$ErrorActionPreference = "Stop"
$alerts = @{}
$result = $null
$scomMonitoringObject = Get-SCOMMonitoringObject -Id $storageObjectId
if ($null -eq $scomMonitoringObject){return $result}
$AlertsCriteria = Get-AlertRuleCriteria
#Get all active SCOM storage alerts from faults rules
$all_active_alerts = Get-AlertsFromObject -mo $scomMonitoringObject -criteria $AlertsCriteria
if ($null -eq $all_active_alerts)
{
return $result
}
$duplicateAlertsToClose = Get-DuplicateAlertsForClose -alerts $all_active_alerts
$IsAllAlerts = $false
if ($null -eq $activefaults -or 0 -eq $activefaults.Count)
{
$IsAllAlerts = $true
}
foreach($alert in $all_active_alerts)
{
$faultId = Get-FaultIdFromAlert -alert $alert
if ($null -ne $faultId -and ($true -eq $IsAllAlerts -or $false -eq $activefaults.ContainsKey($faultId)) )
{
$alerts[$alert] = 1
}
}
if ($null -ne $duplicateAlertsToClose)
{
foreach($alert in $duplicateAlertsToClose.Keys)
{
if ($null -eq $alert) {continue;}
if ($false -eq $alerts.ContainsKey($alert)) { $alerts[$alert] = 1;}
}
}
if (0 -ne $alerts.Count)
{
$result = @($alerts.Keys)
}
return $result
}
Function Check-ScriptArguments($storageObjectId)
{
$ErrorActionPreference = "SilentlyContinue"
$result = $false;
#in some cases CD module works incorrectly
if ([string]::IsNullOrEmpty($EventType) -or "List" -ne $EventType)
{
AddTraceMessage -message "Incorrect DataItem returned. Type is equal to [$EventType] instead of [List]"
return $false
}
$result = $true
return $result
}
Function Log-FinalData()
{
$ErrorActionPreference = "SilentlyContinue"
if ($error -ne $null -and $error.Count -gt 0 -and $error[0] -ne $null)
{
$momAPI.LogScriptEvent($SCRIPT_NAME, $GenericFailureEvent, 1, $error[0].ToString());
}
if ($script:traceMsg -ne $null)
{
$momAPI.LogScriptEvent($SCRIPT_NAME, $GenericInformationEvent, 0, $script:traceMsg);
}
}
Function Prepare-Environment($storageObjectId)
{
$ErrorActionPreference = "SilentlyContinue"
$result = Check-ScriptArguments -storageObjectId $storageObjectId
if ($false -eq $result) {return $result}
$result = Prepare-ScomConnection
return $result
}
Function Process-Faults($storageObjectId)
{
$ErrorActionPreference = "Stop"
try
{
$activeFaults = ParseFaultIds -inpt $faultIds
$alerts = Get-ActiveAlerts -storageObjectId $storageObjectId -activefaults $activeFaults
$AlertCount = $alerts.Count
AddTraceMessage -message "Number of active alerts = $AlertCount"
CloseAlerts -alerts $alerts
}
catch
{
AddTraceMessage -message $_.Exception.Message
}
finally
{
Log-FinalData
}
}
Function PrintTraceMessage
{
#if ($false -eq $DebugMode) { return;}
AddTraceMessage -message "Storage monitoring script CloseAlerts.ps1 started."
AddTraceMessage -message "TargeObjectId : $targetId"
AddTraceMessage -message "StorageObjectId : $storageObjectObjectID"
AddTraceMessage -message "storageObjectUniqueID : $storageObjectUniqueID"
AddTraceMessage -message "FaultId : $faultIds"
AddTraceMessage -message "ItemType : $EventType"
}
Function Main()
{
$ErrorActionPreference = "Stop"
PrintTraceMessage
$storageObjectId = Get-Guid -sguid $targetId
$result = Prepare-Environment -storageObjectId $storageObjectId
if ($false -eq $result)
{
Log-FinalData
return
}
Process-Faults -storageObjectId $storageObjectId
}
Main
</Script> </ScriptBody>
<Parameters>
<Parameter>
<Name>faultIds</Name>
<Value>$Config/FaultId$</Value>
</Parameter>
<Parameter>
<Name>targetId</Name>
<Value>$Config/TargetId$</Value>
</Parameter>
<Parameter>
<Name>storageObjectUniqueID</Name>
<Value>$Config/StorageUniqueID$</Value>
</Parameter>
<Parameter>
<Name>storageObjectObjectID</Name>
<Value>$Config/StorageObjectID$</Value>
</Parameter>
<Parameter>
<Name>EventType</Name>
<Value>$Config/DataType$</Value>
</Parameter>
<Parameter>
<Name>RuleId1</Name>
<Value>$Config/RuleId1$</Value>
</Parameter>
<Parameter>
<Name>RuleId2</Name>
<Value>$Config/RuleId2$</Value>
</Parameter>
<Parameter>
<Name>RuleId3</Name>
<Value>$Config/RuleId3$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="WA">
<Node ID="CD"/>
</Node>
</Composition>
</Composite>
</ModuleImplementation>
<InputType>System!System.BaseData</InputType>
</WriteActionModuleType>