PureStorage.FlashArray.AlertsRuleModules.Powershell.PA (ProbeActionModuleType)

Element properties:

TypeProbeActionModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
Probe ProbeAction Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe Default
WarningFilter ConditionDetection System.ExpressionFilter Default

Overrideable Parameters:

IDParameterTypeSelector
TimeoutSecondsint$Config/TimeoutSeconds$

Source Code:

<ProbeActionModuleType ID="PureStorage.FlashArray.AlertsRuleModules.Powershell.PA" Accessibility="Internal" Batching="false" PassThrough="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" type="xsd:integer" name="TimeoutSeconds"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<ProbeAction ID="Probe" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe">
<ScriptName>AlertsRule.ps1</ScriptName>
<ScriptBody><Script>param($Endpoint, $Username, $Password)

#Import-Module OperationsManager -Verbose
#=================================================================================
# This file gets Alerts from the Pure Array command line
# If you want to test it, remember to generate the alerts with severity either warning or critical,
# because in the XML file, I use severity to separate alerts.
# In our real alerts, the severity is either warning or critical or info (no alerts raised in the console).
#=================================================================================

function AlertsRule {
# Import the SCOM PowerShell module
$ScriptName = "AlertsRule.ps1"
$NUMBER_ALERT_FIELDS = 11

LoadOperationsManagerModule $ScriptName

# Gather script start time
$StartTime = Get-Date
# Gather who the script is running as
$WhoAmI = whoami

# Load MomScript API
$momapi = new-object -comObject 'MOM.ScriptAPI'
Log $ScriptName $GLOBAL:INFO_LEVEL "Starting script $Endpoint"
LoadPowerShellSDK $ScriptName

# Connect to FlashArray and get alert messages
$Password = $Password | ConvertTo-SecureString -AsPlainText -Force
try {
$IgnoreCertErrors = GetIgnoreCertErrors $true
$FlashArray = New-PfaArray -EndPoint $Endpoint -UserName $Username -Password $Password -ClientName $GLOBAL:clientName -ClientVersion $GLOBAL:mpVersion -IgnoreCertificateError:$IgnoreCertErrors -HttpTimeOutInMilliSeconds 60000
} catch {
Log $ScriptName $GLOBAL:ERROR_LEVEL "Connection to array failed on these credentials. $Username. Check that the PurePowershell cmdlet is installed, and your credentials are correct. Error: $_"
exit
}

# $CLIMessages is the String output of CLI. Only get all the open alerts, if there is no open messages, only output ""
$CLIMessages = New-PfaCLICommand -EndPoint $Endpoint -UserName $Username -Password $Password -CommandText "puremessage list --open --csv --notitle"
$CLIMessages = $CLIMessages.trim()
Log $ScriptName $Global:VERBOSE_LEVEL "CLI message output: $CLIMessages"
$Warning = "No"

# Get group of PureArray
$Group = Get-SCOMGroup -DisplayName "*Pure Array*"

# Get the instances of this particular array
$ArrayInstance = $Group.GetRelatedMonitoringObjects() | where {$_.DisplayName -eq $Endpoint}

# Get Alerts sorted with most recent first
$SCOMAlerts = Get-SCOMAlert -Instance $ArrayInstance -ResolutionState 0 | where {$_.name -like "*REST API*"}
$SCOMAlerts = $SCOMAlerts | Sort-Object -Descending LastModified
Log $ScriptName $GLOBAL:INFO_LEVEL "SCOM Alerts: $SCOMAlerts"

# If the alerts are null, we don't need to do anything or else we need to resolve the CLOSED alerts in the console
if ($SCOMAlerts -ne $null)
{
$allCLIMessages = New-PfaCLICommand -EndPoint $Endpoint -UserName $Username -Password $Password -CommandText "puremessage list --csv --notitle"
$allCLIMessages = $allCLIMessages.trim()
$allCLIMessages = $allCLIMessages.split("`n")
$ClosedCLIMessages = @()
foreach($allMessage in @($allCLIMessages).trim())
{
if(@($CLIMessages) -notcontains $allMessage)
{
$ClosedCLIMessages += $allMessage
}
}

foreach($closedMessage in @($ClosedCLIMessages))
{
Log $ScriptName $GLOBAL:INFO_LEVEL "closedMessage: $closedMessage"
$closedAlert = Get-SCOMAlert -Instance $ArrayInstance -ResolutionState 0 | where {$_.name -like "$($closedMessage.split(",")[0]) *"}
if($closedAlert)
{
Log $ScriptName $GLOBAL:INFO_LEVEL "resolving alert: $closedAlert"
Resolve-SCOMAlert -Alert $closedAlert
}
}
}

# If $CLIMessages are null, just return bag with no warnings
if ($CLIMessages -eq $null -or $CLIMessages.Length -eq 0) {
Log $ScriptName $GLOBAL:INFO_LEVEL "No alert messages"
$Warning = "No"
$bag = $momapi.CreatePropertyBag()
$bag.AddValue('Warning',$Warning)
$bag

} else {
# Parse the output of the command line. The first line is attributes names, the last line is "" (empty string).
# The other lines in the $MessageArrays are open alert messages that are separated by commas
# All the fields(11): ID, Time, Severity, Category, Code, Component, Name, Event, Expected, Actual, Details
# $AlertMessages is an array of alert messages
$NewAlertMessages = $CLIMessages.Split("`n") | foreach {$_.trim()}
$length = @($NewAlertMessages).Length
Log $ScriptName $GLOBAL:WARNING_LEVEL "`nFound $length open alert messages"

# Adding new alerts
Log $ScriptName $GLOBAL:INFO_LEVEL "`nNo SCOM Alerts exist, adding all new CLI alerts...`n"
$Warning = "Yes"
foreach($AlertMessage in $NewAlertMessages) {
if ($AlertMessage.Length -eq 0) {
continue
}
$dict = Parse-Alert $AlertMessage

# Get all the fields.
$Id = $dict.Get_Item('Id')
$TimeOpened = $dict.Get_Item('TimeOpened')
$Severity = $dict.Get_Item('Severity')
$Category = $dict.Get_Item('Category')
$Code = $dict.Get_Item('Code')
$Component = $dict.Get_Item('Component')
$Name = $dict.Get_Item('Name')
$Event = $dict.Get_Item('Event')
$Expected = $dict.Get_Item('Expected')
$Actual = $dict.Get_Item('Actual')
$Details = $dict.Get_Item('Details')

$URL = "https://support.purestorage.com/?cid=Alert_00"
if ($Code -lt 10) {
$URL = "https://support.purestorage.com/?cid=Alert_000" + $Code
} else {
$URL = "https://support.purestorage.com/?cid=Alert_00" + $Code
}

$bag = $momapi.CreatePropertyBag()
# Add the necessary properties to the object and add the object to the return bag
$bag.AddValue('Warning',$Warning)
$bag.AddValue('ID',$Id)
$bag.AddValue('TimeOpened',$TimeOpened)
$bag.AddValue('Severity',$Severity)
$bag.AddValue('Category',$Category)
$bag.AddValue('Code',$Code)
$bag.AddValue('Component',$Component)
$bag.AddValue('Name',$Name)
$bag.AddValue('Event',$Event)
$bag.AddValue('Expected',$Expected)
$bag.AddValue('Actual',$Actual)
$bag.AddValue('Details',$Details)
$bag.AddValue('URL',$URL)

Log $ScriptName $GLOBAL:WARNING_LEVEL "`nNew alert: $Code, go to $URL"
$bag
#}
}
}

$EndTime = Get-Date
$ScriptTime = ($EndTime - $StartTime).TotalSeconds
Log $ScriptName $GLOBAL:INFO_LEVEL "Script has completed at $Endpoint. Runtime was ($ScriptTime) seconds."

Disconnect-PfaArray -Array $FlashArray
}

function Parse-Alert($AlertMessage)
{
$dict = @{}
if(!$AlertMessage) { Log $ScriptName $Global:ERROR_LEVEL "Alert message is null or empty"; return $dict }
$Fields = $AlertMessage.Split(",")
if($Fields.length -ne $NUMBER_ALERT_FIELDS) { Log $ScriptName $Global:ERROR_LEVEL "Alert message has incorrect number of fields. Failed message: $AlertMessage" }
else
{
$dict.Add('Id', [int32]$Fields[0])
$dict.Add('TimeOpened', [datetime]$Fields[1])
$dict.Add('Severity', $Fields[2])
$dict.Add('Category', $Fields[3])
$dict.Add('Code', $Fields[4])
$dict.Add('Component', $Fields[5])
$dict.Add('Name', $Fields[6])
$dict.Add('Event', $Fields[7])
$dict.Add('Expected', $Fields[8])
$dict.Add('Actual', $Fields[9])
$dict.Add('Details', $Fields[10])
}
return $dict
}
function SetLogLevel ($LogLevel){
Write-Host "Setting LogLevel to $LogLevel"
if ($LogLevel -ge 1 -and $LogLevel -le 4){
New-Item -Path HKLM:\SOFTWARE\PureStorage\SCOM -Name LogLevel -Force
Set-Item -Path HKLM:\SOFTWARE\PureStorage\SCOM\LogLevel -Value $LogLevel
$GLOBAL:CURRENT_LOG_LEVEL = $LogLevel
}
}

function GetLogLevel ($default){
if (Test-Path HKLM:\SOFTWARE\PureStorage\SCOM\LogLevel){
$item = Get-ItemProperty "HKLM:\SOFTWARE\PureStorage\SCOM\LogLevel"
$log_level = $item.'(default)'
$log_level
}
else
{
$default
}
}

function SetIgnoreCertErrors ($value){
Write-Host "Setting IgnoreCertErros to $value"
New-Item -Path HKLM:\SOFTWARE\PureStorage\SCOM -Name IgnoreCertErrors -Force
Set-Item -Path HKLM:\SOFTWARE\PureStorage\SCOM\IgnoreCertErrors -Value $value
}

function GetIgnoreCertErrors ($default){
if (Test-Path HKLM:\SOFTWARE\PureStorage\SCOM\IgnoreCertErrors){
$item = Get-ItemProperty "HKLM:\SOFTWARE\PureStorage\SCOM\IgnoreCertErrors"
$log_level = [bool]($item.'(default)')
$log_level
}
else
{
$default
}
}


function InitLogging () {
$GLOBAL:MOMAPI = New-Object -comObject "Mom.ScriptAPI"
$GLOBAL:mpVersion = (Get-SCOMManagementPack -name "PureStorageFlashArray").Version.ToString()
if(!$GLOBAL:mpVersion) {$GLOBAL:mpVersion = 'unknown'}
$GLOBAL:clientName = "SCOM"
##### LOG LEVEL ####
# 1 Errors
# 2 Warnings
# 3 Information
# 4 Verbose
$GLOBAL:ERROR_LEVEL = 1
$GLOBAL:WARNING_LEVEL = 2
$GLOBAL:INFO_LEVEL = 3
$GLOBAL:VERBOSE_LEVEL = 4
$GLOBAL:CURRENT_LOG_LEVEL = GetLogLevel $GLOBAL:VERBOSE_LEVEL

$GLOBAL:LOG_CODES_MAP = @{}
$GLOBAL:DEFAULT_LOG_CODE = 5555
################## Discoveries ##################
$GLOBAL:LOG_CODES_MAP.Add("PureVolumeDiscovery.ps1", 2001)
$GLOBAL:LOG_CODES_MAP.Add("PurePortDiscovery.ps1", 2002)
$GLOBAL:LOG_CODES_MAP.Add("PureHostDiscovery.ps1", 2003)
$GLOBAL:LOG_CODES_MAP.Add("PureControllerDiscovery.ps1", 2004)
$GLOBAL:LOG_CODES_MAP.Add("PureArrayDiscovery.ps1", 2005)
$GLOBAL:LOG_CODES_MAP.Add("InitialArrayDiscovery.ps1", 2006)
##################### Rules #######################
$GLOBAL:LOG_CODES_MAP.Add("AlertsRule.ps1", 2101)
$GLOBAL:LOG_CODES_MAP.Add("ArrayPerformanceRule.ps1", 2102)
$GLOBAL:LOG_CODES_MAP.Add("HostgroupPerformanceRule.ps1", 2103)
$GLOBAL:LOG_CODES_MAP.Add("HostPerformanceRule.ps1", 2104)
$GLOBAL:LOG_CODES_MAP.Add("VolumePerformanceRule.ps1", 2105)
#################### Monitors ######################
$GLOBAL:LOG_CODES_MAP.Add("AlertsRuleMonitor.ps1", 2201)
$GLOBAL:LOG_CODES_MAP.Add("ArrayIOSpaceMonitor.ps1", 2202)
$GLOBAL:LOG_CODES_MAP.Add("ConnectionHealthMonitor.ps1", 2203)
$GLOBAL:LOG_CODES_MAP.Add("ControllerHealthMonitor.ps1", 2204)
$GLOBAL:LOG_CODES_MAP.Add("VolumeIOMonitor.ps1", 2205)
$GLOBAL:LOG_CODES_MAP.Add("HostIOMonitor.ps1", 2206)
$GLOBAL:LOG_CODES_MAP.Add("PortHealthMonitor.ps1", 2207)
##################### Tasks #######################
$GLOBAL:LOG_CODES_MAP.Add("NewHostTask.ps1", 2301)
$GLOBAL:LOG_CODES_MAP.Add("NewVolumeTask.ps1", 2302)
$GLOBAL:LOG_CODES_MAP.Add("VerifyEndpointTask.ps1", 2303)
################### Dashboards ####################
$GLOBAL:LOG_CODES_MAP.Add("PureVolumeState.ps1", 2401)
$GLOBAL:LOG_CODES_MAP.Add("PureArrayDashboardIOPSData.ps1", 2402)
$GLOBAL:LOG_CODES_MAP.Add("PureArrayDashboardLatencyData.ps1", 2403)
$GLOBAL:LOG_CODES_MAP.Add("PureArrayDashboardBandwidthData.ps1", 2404)
$GLOBAL:LOG_CODES_MAP.Add("PureHostState.ps1", 2405)
$GLOBAL:LOG_CODES_MAP.Add("PureArrayDashboardSpaceMetricsData.ps1", 2406)
}

function GetLogCode ($filename) {
$code = $GLOBAL:LOG_CODES_MAP[$filename]
if ($code -eq $null) {
$code = $DEFAULT_LOG_CODE
}
return $code
}

function GetSCOMLogLevel ($level) {
switch ($level){
$GLOBAL:ERROR_LEVEL {1}
$GLOBAL:WARNING_LEVEL {2}
$GLOBAL:INFO_LEVEL {0}
$GLOBAL:VERBOSE_LEVEL {0}
}
}

function Log ($script_name, $level, $message) {
if ($level -le $GLOBAL:CURRENT_LOG_LEVEL){
$code = GetLogCode $script_name
$level = GetSCOMLogLevel $level
if($GLOBAL:mpVersion -eq 'unknown') {$GLOBAL:mpVersion = (Get-SCOMManagementPack -name "PureStorageFlashArray").Version.ToString()}
$fullScriptName = "$script_name" + " [$GLOBAL:mpVersion]"
$GLOBAL:MOMAPI.LogScriptEvent($fullScriptName, $code, $level, $message)
}
}

function LoadPowerShellSDK ($script_name){
Log $script_name $GLOBAL:VERBOSE_LEVEL "Importing PowerShell SDK in $script_name"

try {
$PurePowerShellSDKKey = Get-ItemProperty "HKLM:\SOFTWARE\PureStorage\SCOM\PowerShellSDKPath"
$PurePowerShellSDKLocation = $PurePowerShellSDKKey.'(default)'
Log $script_name $GLOBAL:VERBOSE_LEVEL "Importing PowerShell SDK from $PurePowerShellSDKLocation"
Import-Module $PurePowerShellSDKLocation -Verbose
}
catch {
Log $script_name $GLOBAL:ERROR_LEVEL "Failed to import PowerShell SDK from $PurePowerShellSDKLocation"
}
}

function LoadOperationsManagerModule ($script_name)
{
Log $script_name $GLOBAL:INFO_LEVEL "Importing Operations Manager module in $script_name"
try
{
# https://blogs.technet.microsoft.com/cchamp/2015/09/30/loading-the-scom-powershell-module-for-real-this-time/
$OMCmdletsTest = (Get-Module|% {$_.Name}) -Join ' '
If (!$OMCmdletsTest.Contains('OperationsManager')) {
$ModuleFound = $false
$SetupKeys = @('HKLM:\Software\Microsoft\Microsoft Operations Manager\3.0\Setup',
'HKLM:\SOFTWARE\Microsoft\System Center Operations Manager\12\Setup')
foreach($setupKey in $SetupKeys) {
If ((Test-Path $setupKey) -and ($ModuleFound -eq $false)) {
$setupKey = Get-Item -Path $setupKey
$installDirectory = $setupKey.GetValue('InstallDirectory')
$psmPath = $installdirectory + '\Powershell\OperationsManager\OperationsManager.psm1'
If (Test-Path $psmPath) {
$ModuleFound = $true
}
}
}
If ($ModuleFound) {
Import-Module $psmPath
} else {
Import-Module OperationsManager
}
}
else { Log $ScriptName $GLOBAL:INFO_LEVEL "Operations Manager module is already present" }
}
catch
{
Log $script_name $GLOBAL:INFO_LEVEL "Failed to import Operations Manager: $_"
}
}

InitLogging


AlertsRule
</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>Endpoint</Name>
<Value>$Target/Property[Type="PureStorage.FlashArray.PureArray"]/Endpoint$</Value>
</Parameter>
<Parameter>
<Name>Username</Name>
<Value>$RunAs[Name="PureStorage.FlashArray.FlashArrayAdminAccount"]/UserName$</Value>
</Parameter>
<Parameter>
<Name>Password</Name>
<Value>$RunAs[Name="PureStorage.FlashArray.FlashArrayAdminAccount"]/Password$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</ProbeAction>
<ConditionDetection ID="WarningFilter" TypeID="System!System.ExpressionFilter">
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="String">Property[@Name='Warning']</XPathQuery>
</ValueExpression>
<Operator>Equal</Operator>
<ValueExpression>
<Value Type="String">Yes</Value>
</ValueExpression>
</SimpleExpression>
</Expression>
</ConditionDetection>
</MemberModules>
<Composition>
<Node ID="Probe"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
<TriggerOnly>true</TriggerOnly>
</ProbeActionModuleType>