共用方式為


教學課程:透過自動化使用 Webhook 建立前置和後置事件

適用於:✔️ Windows VM ✔️ Linux VM ✔️ 內部部署環境 ✔️ Azure VMs ✔️ 已啟用 Azure Arc 的伺服器。

前置和後置事件,也稱為前置/後置指令碼,可讓您在排程修補程式安裝前後執行使用者定義的動作。 最常見的案例之一是啟動和停止虛擬機器 (VM)。 透過前置事件,您可以執行預先修補指令碼來啟動 VM,再起始排程修補程序。 排程修補完成且伺服器重新啟動後,就可以執行修補後置指令碼,以安全地關閉 VM。

本教學課程說明如何使用 Webhook 建立前置和後置事件,以在排程修補工作流程中啟動和停止 VM。

在本教學課程中,您會了解如何:

  • 必要條件
  • 建立及發佈自動化 Runbook
  • 新增 Webhook
  • 建立事件訂閱

必要條件

  1. 請確定您使用 PowerShell 7.2 Runbook。

  2. 將權限指派給受控識別 - 您可將權限指派給適當的受控識別。 Runbook 可以使用自動化帳戶的系統指派受控識別或使用者指派的受控識別。

    您可使用入口網站或 PowerShell Cmdlet,將權限指派給每個身分識別:

    請遵循使用 Azure 入口網站指派 Azure 角色中的步驟來指派權限


  1. 匯入 Az.ResourceGraph 模組,確定模組已更新至包含模組 2.0.3 版的 ThreadJob。

建立及發佈自動化 Runbook

  1. 登入 Azure 入口網站,然後移至 [Azure 自動化] 帳戶

  2. 建立發佈自動化 Runbook。

  3. 如果您使用在 Azure 自動化更新管理中用於前置和後置工作的 Runbook,請務必遵循下列步驟,以避免對機器造成非預期的影響,且維護執行失敗。

    1. 針對 Runbook,剖析 Webhook 承載以確保其只會在 Microsoft.Maintenance.PreMaintenanceEventMicrosoft.Maintenance.PostMaintenanceEvent 事件上觸發。 如果有任何其他事件以相同的端點新增,則設計上會在其他訂用帳戶事件上觸發 Webhook。

      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  
      } 
      
    2. SoftwareUpdateConfigurationRunContext 參數,其中包含更新部署中機器清單的相關資訊,當您在使用自動化 Webhook 時,不會將其用於前置和後置事件的前置和後置指令碼。 您可以從 Azure Resource Graph 查詢機器清單,或讓機器清單在指令碼中進行編碼。

      • 請確定已將適當的角色和權限授與您在指令碼中所使用的受控識別、執行 Resource Graph 查詢,以及啟動或停止電腦。
      • 查看資源圖表查詢的相關權限
      • 請參閱虛擬機器參與者角色
      • 請參閱下列程式碼:
    3. 請參閱 Webhook 承載

      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    
      }
      }
      
    4. 若要自訂,您可以使用已完成上述修改的現有指令碼,或使用下列指令碼。

範例指令碼

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 
    } 
} 

新增 Webhook

將 Webhook 新增至上述已發佈的 Runbook,並複製 Webhook URL。

注意

在建立 Webhook 之後請務必複製 URL,因為您無法再次擷取該 URL。

建立事件訂閱

  1. 登入 [Azure 入口網站],然後移至 [Azure 更新管理員]

  2. 在 [管理] 底下,選取 [機器]、[維護設定]

  3. 在 [維護組態] 頁面上,選取組態。

  4. 在 [設定] 之下,選取 [事件]

    顯示選取 [事件] 功能表選項的選項螢幕擷取畫面。

  5. 選取 [+ 事件訂用帳戶] 以建立維護前/後的事件。

    顯示選取事件訂用帳戶選項的螢幕擷取畫面。

  6. 在 [建立事件訂用帳戶] 頁面上,輸入下列詳細資料:

    1. 在 [事件訂用帳戶詳細資料] 區段中,提供適當的名稱。
    2. 將結構描述保留為 [事件方格結構描述]
    3. 在 [事件類型] 區段中,[篩選至事件類型]
      1. 針對事前事件選取 [維護前事件]
        • 在 [端點詳細資料] 區段中,選取 [Webhook] 端點,然後選取 [設定端點]
        • 提供適當的詳細資料,例如前置事件 Webhook URL 來觸發事件。
      2. 針對事後事件選取 [維護後事件]
        • 在 [端點詳細資料] 區段中,選取 [Webhook] 端點,然後選取 [設定端點]
        • 提供適當的詳細資料,例如後置事件 Webhook URL 來觸發此事件。 顯示建立事件訂用帳戶選項的螢幕擷取畫面。
  7. 選取 建立

下一步