########################################################################### # # NAME: Solarwinds-AckFromVictorOps.ps1 # # AUTHOR: Sean Stark # # Purpose: Gets VictorOps Alerts from REST API. Parses through each alert and acks or clears the associated alert in Solarwinds. # # Current Limitations: - You may be limited to the number of VictorOps API calls depending on your subscription # - The VictorOps incidents API endpoint does not return any custom fields you may be sending. # - Unable to set the AcknowledgedBy field. This will always show the service account running the script. # ########################################################################### # # Updated to v2 by VictorOps in April 2019 # ########################################################################### # # # ############ Variables ############## #Victor Ops Company ID $API_ID = "" #Victor Ops API Key $ApiKey = "" #Set to your SolarWinds Primary Application Server $SolarWindsServer = "" #Victor Ops API Url for Incidents $API_URL = "https://api.victorops.com/api-public/v1/incidents" #Create a Header Object for the Rest Request $headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]' $headers.Add("X-VO-Api-Key", $ApiKey) $headers.Add("X-VO-Api-Id", $API_ID) #Ignore SSL Certificate Trusts add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ ###################################### #Add the Solarwinds SDK Snapin # Add-PSSnapin SwisSnapin Import-Module SwisPowerShell #Create Crendential Object from the SolarWinds Creds $Creds = Get-Credential -Credential ${Credential} #Create SWIS connection object $Swis = Connect-Swis -Hostname $SolarWindsServer -Credential $Creds #Invoke the Rest Method, get Incidents try{ $Incidents = Invoke-RestMethod -Method Get -Uri $API_URL -ContentType "application/json" -Headers $headers } Catch{ Write-Host "Message: $($Error[0])" exit 1; } #If there are not current Incidents update stat to 0 If ($Incidents.incidents.Count -le 0){ Write-Host "Statistic.TotalIncidents:" 0; exit 0; } #Check for Incidents If($Incidents){ #Get Just Acked and Resolved incidents $ACKED = @($Incidents.incidents | Where-Object {$_.currentPhase -eq "ACKED"}) $RESOLVED = @($Incidents.incidents | Where-Object {$_.currentPhase -eq "RESOLVED"}) $UNACKED = @($Incidents.incidents | Where-Object {$_.currentPhase -eq "UNACKED"}) #Output TotalIncidents Write-Host "Statistic.TotalIncidents: $($Incidents.incidents.Count)" Write-Host "Statistic.TotalAcked: $($ACKED.Count)" Write-Host "Statistic.TotalResolved: $($RESOLVED.Count)" #Select Unique incidents from ACKED, Resolved, and Unacked State. The same incident can show up in Resolved and Unacked if it is a repeating issue. We don't want to clear the incident in this case. $RESOLVED = $RESOLVED | Where-Object {($_.entityId -notin $ACKED.entityId) -and ($_.entityId -notin $UNACKED.entityId)} $Incidents = $ACKED + $RESOLVED #Loop through each incident ForEach ($Incident in $Incidents){ #Set the Incident Values to Variables, its possible victorops could change this in the future $AlertTitle = $Incident.entityDisplayName $AlertAuthor = $Incident.transitions.by $AlertID = $Incident.entityId $AlertState = $Incident.CurrentPhase $AlertMessage = "$($Incident.transitions.message) | Acked By: $($Incident.transitions.by)" $AlertPagedUsers = $Incident.pagedUsers #Output for Debug Write-Host " " Write-Host "Alert ID: $AlertID" -ForegroundColor Green Write-Host "Alert Title: $AlertTitle" Write-Host "Alert Author: $AlertAuthor" Write-Host "Alert Acked By: $AlertMessage" Write-Host "Alert State: $AlertState" Write-Host "Alert Paged Users: $AlertPagedUsers" #Check for a null message value and set to blank If(!($AlertMessage)){$AlertMessage = " "} #Define the SQL Query to find the Alert in the Orion.AlertStatus Table $Query = "SELECT AlertActiveID, AlertObjectID FROM Orion.AlertActive Where AlertObjectID = $AlertID" #Query the Solarwinds Orion.AlertStatus Table for the Alert. try{ $AlertQuery = Get-SwisData $swis $Query } catch{Write-Host "$($Error[0])"} #Convert AlertID to an Array of Integers. This is to support the Solarwinds ACK Parameter $AlertID = @($AlertID -as [int]) #Check for Results If($AlertQuery){ #Ack the Alert from Solarwinds if Acked If($Incident.CurrentPhase -eq "ACKED"){ Write-Host "Acking Alert" -ForegroundColor Red #Create and XML String for Acking the Alert in Solarwinds $xmlString = " $($AlertID) " $xmlElement = ([xml]$xmlString).DocumentElement #Ack Alert Invoke-SwisVerb $swis Orion.AlertActive Acknowledge @( $xmlElement,$AlertMessage) } #Clear the Alert from Solarwinds if Resolved If($Incident.CurrentPhase -eq "RESOLVED"){ Write-Host "Clearing Alert" -ForegroundColor Red #Create and XML String for Acking the Alert in Solarwinds $xmlString = " $($AlertID) " $xmlElement = ([xml]$xmlString).DocumentElement #Clear the Alert Invoke-SwisVerb $swis Orion.AlertActive ClearAlert @( $xmlElement ) } } } }