Tutorial: Create pre and post events using a webhook with Automation
Applies to: ✔️ Windows VMs ✔️ Linux VMs ✔️ On-premises environment ✔️ Azure VMs ✔️ Azure Arc-enabled servers.
Pre and post events, also known as pre/post-scripts, allow you to execute user-defined actions before and after the schedule patch installation. One of the most common scenarios is to start and stop a Virtual Machine (VM). With pre-events, you can run a prepatching script to start the VM before initiating the schedule patching process. Once the schedule patching is complete, and the server is rebooted, a post-patching script can be executed to safely shut down the VM.
This tutorial explains how to create pre and post events to start and stop a VM in a schedule patch workflow using a webhook.
In this tutorial, you learn how to:
- Prerequisites
- Create and publish Automation runbook
- Add webhooks
- Create an event subscription
Prerequisites
Ensure that you are using PowerShell 7.2 runbook.
Assign permission to managed identities - You can assign permissions to the appropriate managed identity. The runbook can use either the Automation account system-assigned managed identity or a user-assigned managed identity.
You can use either portal or PowerShell cmdlets to assign permissions to each identity:
Follow the steps in Assign Azure roles using the Azure portal to assign permissions
- Import the
Az.ResourceGraph
module, ensure the module is updated to ThreadJob with the module version 2.0.3.
Create and publish Automation runbook
Sign in to the Azure portal and go to your Azure Automation account
If you were using Runbooks that were being used for pre or post tasks in Azure Automation Update Management, it's critical that you follow the below steps to avoid an unexpected impact to your machines and failed maintenance runs.
For your runbooks, parse the webhook payload to ensure that it's triggering on Microsoft.Maintenance.PreMaintenanceEvent or Microsoft.Maintenance.PostMaintenanceEvent events only. By design webhooks are triggered on other subscription events if any other event is added with the same endpoint.
- See the Azure Event Grid event schema.
- See the Event Grid schema specific to Maintenance configurations
- See the code listed below:
param ( [Parameter(Mandatory=$false)] [object] $WebhookData ) $notificationPayload = ConvertFrom-Json -InputObject $WebhookData.RequestBody $eventType = $notificationPayload[0].eventType if ($eventType -ne "Microsoft.Maintenance.PreMaintenanceEvent" -and $eventType –ne "Microsoft.Maintenance.PostMaintenanceEvent" ) { Write-Output "Webhook not triggered as part of pre or post patching for maintenance run" return }
SoftwareUpdateConfigurationRunContext parameter, which contains information about list of machines in the update deployment won't be passed to the pre or post scripts when you use them for pre or post events while using automation webhook. You can either query the list of machines from Azure Resource Graph or have the list of machines coded in the scripts.
- Ensure that proper roles and permissions are granted to the managed identities that you're using in the script, to execute Resource Graph queries and to start or stop machines.
- See the permissions related to resource graph queries
- See Virtual machines contributor role.
- See the code listed below:
See webhook payload
param ( [Parameter(Mandatory=$false)] [object] $WebhookData ) Connect-AzAccount -Identity # Install the Resource Graph module from PowerShell Gallery # Install-Module -Name Az.ResourceGraph $notificationPayload = ConvertFrom-Json -InputObject $WebhookData.RequestBody $maintenanceRunId = $notificationPayload[0].data.CorrelationId $resourceSubscriptionIds = $notificationPayload[0].data.ResourceSubscriptionIds if ($resourceSubscriptionIds.Count -gt 0) { Write-Output "Querying ARG to get machine details[MaintenanceRunId=$maintenanceRunId][ResourceSubscriptionIdsCount=$($resourceSubscriptionIds.Count)]" $argQuery = @"maintenanceresources | where type =~ 'microsoft.maintenance/applyupdates' | where properties.correlationId =~ '$($maintenanceRunId)' | where id has '/providers/microsoft.compute/virtualmachines/' | project id, resourceId = tostring(properties.resourceId) | order by id asc "@ Write-Output "Arg Query Used: $argQuery" $allMachines = [System.Collections.ArrayList]@() $skipToken = $null $res = Search-AzGraph -Query $argQuery -First 1000 -SkipToken $skipToken -Subscription $resourceSubscriptionIds $skipToken = $res.SkipToken $allMachines.AddRange($res.Data) } while ($skipToken -ne $null -and $skipToken.Length -ne 0) if ($allMachines.Count -eq 0) { Write-Output "No Machines were found." break } }
To customize, you can use either your existing scripts with the above modifications done or use the following scripts.
Sample scripts
param
(
[Parameter(Mandatory=$false)]
[object] $WebhookData
)
Connect-AzAccount -Identity
# Install the Resource Graph module from PowerShell Gallery
# Install-Module -Name Az.ResourceGraph
$notificationPayload = ConvertFrom-Json -InputObject $WebhookData.RequestBody
$eventType = $notificationPayload[0].eventType
if ($eventType -ne "Microsoft.Maintenance.PreMaintenanceEvent") {
Write-Output "Webhook not triggered as part of pre-patching for maintenance run"
return
}
$maintenanceRunId = $notificationPayload[0].data.CorrelationId
$resourceSubscriptionIds = $notificationPayload[0].data.ResourceSubscriptionIds
if ($resourceSubscriptionIds.Count -eq 0) {
Write-Output "Resource subscriptions are not present."
break
}
Write-Output "Querying ARG to get machine details [MaintenanceRunId=$maintenanceRunId][ResourceSubscriptionIdsCount=$($resourceSubscriptionIds.Count)]"
$argQuery = @"
maintenanceresources
| where type =~ 'microsoft.maintenance/applyupdates'
| where properties.correlationId =~ '$($maintenanceRunId)'
| where id has '/providers/microsoft.compute/virtualmachines/'
| project id, resourceId = tostring(properties.resourceId)
| order by id asc
"@
Write-Output "Arg Query Used: $argQuery"
$allMachines = [System.Collections.ArrayList]@()
$skipToken = $null
do
{
$res = Search-AzGraph -Query $argQuery -First 1000 -SkipToken $skipToken -Subscription $resourceSubscriptionIds
$skipToken = $res.SkipToken
$allMachines.AddRange($res.Data)
} while ($skipToken -ne $null -and $skipToken.Length -ne 0)
if ($allMachines.Count -eq 0) {
Write-Output "No Machines were found."
break
}
$jobIDs= New-Object System.Collections.Generic.List[System.Object]
$startableStates = "stopped" , "stopping", "deallocated", "deallocating"
$allMachines | ForEach-Object {
$vmId = $_.resourceId
$split = $vmId -split "/";
$subscriptionId = $split[2];
$rg = $split[4];
$name = $split[8];
Write-Output ("Subscription Id: " + $subscriptionId)
$mute = Set-AzContext -Subscription $subscriptionId
$vm = Get-AzVM -ResourceGroupName $rg -Name $name -Status -DefaultProfile $mute
$state = ($vm.Statuses[1].DisplayStatus -split " ")[1]
if($state -in $startableStates) {
Write-Output "Starting '$($name)' ..."
$newJob = Start-ThreadJob -ScriptBlock { param($resource, $vmname, $sub) $context = Set-AzContext -Subscription $sub; Start-AzVM -ResourceGroupName $resource -Name $vmname -DefaultProfile $context} -ArgumentList $rg, $name, $subscriptionId
$jobIDs.Add($newJob.Id)
} else {
Write-Output ($name + ": no action taken. State: " + $state)
}
}
$jobsList = $jobIDs.ToArray()
if ($jobsList)
{
Write-Output "Waiting for machines to finish starting..."
Wait-Job -Id $jobsList
}
foreach($id in $jobsList)
{
$job = Get-Job -Id $id
if ($job.Error)
{
Write-Output $job.Error
}
}
Add webhooks
Add webhooks to the above published runbooks and copy the webhooks URLs.
Note
Ensure to copy the URL after you create a webhook as you cannot retrieve the URL again.
Create an Event subscription
Sign in to the Azure portal and go to your Azure Update Manager.
Under Manage, select Machines, Maintenance Configuration.
On the Maintenance Configuration page, select the configuration.
Under Settings, select Events.
Select +Event Subscription to create a pre/post maintenance event.
On the Create Event Subscription page, enter the following details:
- In the Event Subscription Details section, provide an appropriate name.
- Keep the schema as Event Grid Schema.
- In the Event Types section, Filter to Event Types.
- Select Pre Maintenance Event for a pre-event.
- In the Endpoint details section, select the Webhook endpoint and select Configure an Endpoint.
- Provide the appropriate details such as pre-event webhook URL to trigger the event.
- Select Post Maintenance Event for a post-event.
- Select Pre Maintenance Event for a pre-event.
Select Create.
Next steps
- Learn more on the overview of pre and post events in Azure Update Manager.
- Learn more on how to create pre and post events
- To learn on how to manage pre and post events or to cancel a schedule run, see pre and post maintenance configuration events.
- Learn more on how Create pre and post events using Azure Functions.