教程:通过自动化使用 Webhook 创建前期事件和后期事件
适用于:✔️ Windows VM ✔️ Linux VM ✔️ 本地环境 ✔️ Azure VM ✔️ 已启用 Azure Arc 的服务器。
前置事件和后置事件(也称为前/后脚本)允许你在计划补丁安装前后执行用户定义的操作。 最常见的方案之一是启动和停止 VM。 使用前置事件,可以在启动计划修补过程之前运行预修补脚本来启动 VM。 计划修补完成和重新启动服务器后,可以执行修补后脚本以安全关闭 VM。
本教程介绍如何使用 Webhook 创建前置事件和后置事件,以在计划修补工作流中启动和停止 VM。
本教程介绍如何执行下列操作:
- 先决条件
- 创建和发布自动化 Runbook
- 添加 Webhook
- 创建事件订阅
先决条件
确保使用的是 PowerShell 7.2 Runbook。
向托管标识分配权限 - 可以将权限分配给相应的托管标识。 Runbook 可使用自动化帐户的系统分配的托管标识或用户分配的托管标识。
可以使用门户或 PowerShell cmdlet 向每个标识分配权限:
- 导入
Az.ResourceGraph
模块,确保使用模块版本 2.0.3 将模块更新到 ThreadJob。
创建和发布自动化 Runbook
登录到 Azure 门户并转到“Azure 自动化”帐户
如果使用的 Runbook 用于 Azure 自动化更新管理中的前置或后置任务,请务必按照以下步骤操作,以避免对计算机造成意外影响以及维护运行失败。
对于 Runbook,请解析 Webhook 负载以确保它仅在 Microsoft.Maintenance.PreMaintenanceEvent 或 Microsoft.Maintenance.PostMaintenanceEvent 事件上触发。 根据设计,如果使用同一终结点添加任何其他事件,则其他订阅事件会触发 Webhook。
- 请查看“Azure 事件网格事件架构”。
- 请参阅下面列出的代码:
param ( [Parameter(Mandatory=$false)] [object] $WebhookData ) $notificationPayload = ConvertFrom-Json -InputObject $WebhookData.RequestBody $eventType = $notificationPayload[0].eventType if ($eventType -ne “Microsoft.Maintenance.PreMaintenanceEvent” -or $eventType –ne “Microsoft.Maintenance.PostMaintenanceEvent” ) { Write-Output "Webhook not triggered as part of pre or post patching for maintenance run" return }
SoftwareUpdateConfigurationRunContext 参数,其中包含有关更新部署中计算机列表的信息,在使用自动化 Webhook 期间,如果将其用于前置或后置事件,系统不会将该参数传递到前置或后置脚本。 可以在 Azure Resource Graph 中查询计算机列表,也可以在脚本中编码计算机列表。
- 确保向脚本中使用的托管标识授予适当的角色和权限,以执行 Resource Graph 查询以及启动或停止计算机。
- 查看与 Resource Graph 查询相关的权限
- 请查看虚拟机参与者角色。
- 请参阅下面列出的代码:
查看 Webhook 有效负载
param ( [Parameter(Mandatory=$false)] [object] $WebhookData ) Connect-AzAccount -Environment AzureChinaCloud -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 } }
若要自定义,可以使用完成上述修改的现有脚本或使用以下脚本。
示例脚本
param
(
[Parameter(Mandatory=$false)]
[object] $WebhookData
)
Connect-AzAccount -Environment AzureChinaCloud -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
}
}
添加 Webhook
将 Webhook 添加到上述已发布的 Runbook,并复制 Webhook URL。
注意
确保在创建 Webhook 后复制 URL,因为无法再次检索 URL。
创建事件订阅
登录到 Azure 门户,转到“Azure 更新管理器”。
在“管理”下,选择“计算机”和“维护配置”。
在“维护配置”页上选择“配置”。
在“设置”下,选择“事件”。
选择“+事件订阅”以创建维护前/维护后事件。
在“创建事件订阅”页上,输入以下详细信息:
选择“创建”。
后续步骤
- 有关详细信息,请参阅 Azure 更新管理器中的前置事件和后置事件概述。
- 有关详细信息,请参阅如何创建前置事件和后置事件
- 若要了解如何管理预维护和后期维护事件或取消计划运行,请参阅预维护和后期维护配置事件。
- 有关详细信息,请参阅如何使用 Azure Functions 创建前置和后置事件。