Hello!
My organization has been transitioning more and more of our processes to workflows. One of our biggest issues has been the lack of operational logging for when a workflow fails. See Idea Workflows - Log Activity Success/Failures to | SailPoint Ideas Portal
Below is my attempt using PowerShell and API calls to cut down on some of the toil involved in checking workflows for errors.
It requires the use of:
- Local server to schedule the script on
- Service account to run the task
- Azure key vault to store and retrieve secrets
- An application registration with mail.send capabilities
- A client ID and secret from SailPoint ISC
If you have done something else or perhaps more efficiently than this, please let me know!
## Get failed workflow executions
#region connect to Azure, Get secrets
# Update to require TLS 1.2
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;
# Parameters for AZ Connection
$Params = @{
ApplicationId = '' # App reg with list secret permissions to key vault
Tenant = '' # Tenant ID
CertificateThumbPrint = '' # Certificate thumbprint of the cert signed/created by the svc account running the scheduled task on the server and uploaded to the app reg
}
$TenantId = "" # azure tenant ID needed for graph mail send
$null = Connect-AzAccount @Params # Connecting to azure $null prevents output
# Key vault info for SailPoint ID and secret
$kv = @{
VaultName = '' # Name of the key vault with your SailPoint ISC Client ID and secret
ClientID = '' # Name of the client ID
Secret = '' # Name of the client secret
}
# Get SailPoint secret
Try
{
$client_id = Get-AzKeyVaultSecret -VaultName $kv.VaultName -Name $kv.ClientId -AsPlainText
$client_secret = Get-AzKeyVaultSecret -VaultName $kv.VaultName -Name $kv.Secret -AsPlainText
$null = Disconnect-AzAccount
}
Catch
{
Throw $_ # The script fails if unable to find client ID and secret
}
#endregion connect to Azure, Get secrets
#region get SailPoint ISC access token
# Use the id and secret to get and access token for SailPoint
$oAuthTokenBody = @{
grant_type = "client_credentials"
client_id = $client_id
client_secret = $client_secret
}
# Create token acquisition url
$orgName = "" # Enter the org name here
$baseURL = "https://$orgName.api.identitynow.com"
$oAuthURI = "$baseUrl/oauth/token"
# SailPoint token acquisition and header information
$SPtoken = Invoke-RestMethod -Uri $oAuthURI -Method Post -Body $oAuthTokenBody -ErrorAction Stop
# Set header for API calls
$Headers = @{
Authorization = "$($SPtoken.token_type) $($SPtoken.access_token)"
}
#endregion get SailPoint ISC access token
#region get recent failed workflow executions
# Concatenate the URL
$url = $baseURL + "/v3" + "/workflows"
# Get all active workflows
$results = Invoke-RestMethod -Uri "$url" -Method Get -Headers $Headers
$ActiveWorkflows = $results | Where-Object {$_.enabled -eq $true}
# Retrieve the executions run on each workflow and send email alert on new failures
$failedexecutions = foreach ($ActiveWorkflow in $ActiveWorkflows)
{
$WFID = $ActiveWorkflow.ID # Workflow ID - this endpoint can only get the history of a specific workflow
$url = $BaseURL + "/v3" + "/workflows" + "/$WFID"
# Get all failed workflow executions for the workflow
$results = Invoke-RestMethod -Uri "$url/executions?filters=status eq `"Failed`"" -Method Get -Headers $Headers
# Date for comparing failed execution dates
$date = (Get-Date (Get-Date).AddDays(-1) -Format "o") # This will set the date to 24 hours ago in the proper format
# Create a custom object of only the executions that have failed in the last 24 hours
foreach ($execution in $results)
{
if ($execution.startTime -gt $date)
{
[PSCustomObject]@{
WorkflowName = $ActiveWorkflow.Name
ID = $execution.id
StartTime = $execution.startTime
CloseTime = $execution.closeTime
}
}
}
}
#endregion get recent failed workflow executions
#region send mail notification
if ($failedexecutions) # If failures are present this email will be sent
{
# Format failures from custom object to HTML
$failedfragment = $failedexecutions | ConvertTo-Html -Fragment
# Create message body and properties and send
$MessageParams = @{
subject = "Action Required: Workflow failures detected"
body = @{
contentType = 'HTML'
content = "
<body style='margin:0; padding:0; font-family:'Segoe UI',sans-serif'>
<table style='margin: 0px auto; border-collapse: separate; width: 90%;' width='90%' cellspacing='0' cellpadding='0' align='center'>
<tbody>
<tr>
<td style='width: 1.61812%;' colspan='2'>
<h1 style='text-align: center;'>Workflow failure detected</h1>
</td>
</tr>
<tr>
<td style='padding: 30px 40px 10px; width: 1.61812%;' colspan='2'>
<p style='font-size: 20px;'>What do you need to do?</p>
<p>Find the reason for the failure an re-run the workflow.</p>
Failures: $($failedexecutions.count)<br>
$($failedfragment)
</p>
</td>
</tr>
</tbody>"
}
"toRecipients" = @(
@{
"emailAddress" = @{"address" = "MailTo" }
} )
"ccRecipients" = @(
@{
"emailAddress" = @{"address" = "MailCC" }
}
)
}
# Connect to MG Graph for Mail Send
Connect-MgGraph -ClientId $params.ApplicationId -CertificateThumbprint $Params.CertificateThumbPrint -TenantId $TenantId
Send-MgUserMail -UserId [email protected] -Message $MessageParams
Disconnect-MgGraph
}
else #If NO failures are present this email will be sent
{
# Create message body and properties and send
$MessageParams = @{
subject = "No workflow failures detected today"
body = @{
contentType = 'HTML'
content = "
<body style='margin:0; padding:0; font-family:'Segoe UI',sans-serif'>
<table style='margin: 0px auto; border-collapse: separate; width: 90%;' width='90%' cellspacing='0' cellpadding='0' align='center'>
<tbody>
<tr>
<td style='width: 1.61812%;' colspan='2'>
<h1 style='text-align: center;'>No workflow failures detected</h1>
</td>
</tr>
<tr>
<td style='padding: 30px 40px 10px; width: 1.61812%;' colspan='2'>
<p style='font-size: 20px;'>What do you need to do?</p>
<p>Nothing!</p>
<p>Failures: $($failedexecutions.count)</p>
</td>
</tr>
</tbody>"
}
"toRecipients" = @(
@{
"emailAddress" = @{"address" = "EmailTo" }
} )
"ccRecipients" = @(
@{
"emailAddress" = @{"address" = "EmailCC" }
}
)
}
# Connect to MG Graph for Mail Send
Connect-MgGraph -ClientId $params.ApplicationId -CertificateThumbprint $Params.CertificateThumbPrint -TenantId $TenantId
Send-MgUserMail -UserId [email protected] -Message $MessageParams
Disconnect-MgGraph
}
#endregion send mail notification