📝

Scheduled Event のレスポンスを Log Analytics に保存する

2023/04/04に公開

Azure VM のメンテナンスの通知情報が取得できる Azure Metada Service で取得できる Scheduled Event は通知機能が無かったり過去の情報を取得することができません。そこでScheduled Event API のレスポンスをLog Analytics に保存します。

構成

Windows VM で Scheduled Event API をコールして、そのレスポンスを Data Collection Endpoint へポストするPowershell script をタスクスケジューラーで定期実行します。
(Linux の場合はシェルスクリプトをcron で定期実行すれば同じことが可能です。)

設定

  1. VM のマネージドIDを作成する
    リンク先に従って、ポータルやCLIで設定
    https://learn.microsoft.com/ja-jp/azure/active-directory/managed-identities-azure-resources/qs-configure-portal-windows-vm

  2. Data Collection Endpoint にポストするJSONを決める

{
  "DocumentIncarnation": 0,
  "Events": [],
  "TimeGenerated": "2023-01-01 00:00:00",
  "Hostname": "vm"
}

上記の様にLog Analytics に保存していくデータの形式を決定します

  1. Log Analytics にDCR-Basedのカスタムログテーブルを作成する
    前項で作成したjsonをアップロードしてスキーマを登録します

  2. カスタムログテーブル作成時に関連付けしたらData Collection Ruleリソースの監視メトリック発行者ロールをVMのマネージドIDに割り当てる
    リンク先に従って、ポータルやCLIで設定
    https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/tutorial-logs-ingestion-portal#assign-permissions-to-the-dcr

  3. VM にpowershell script を配置する

$DceURI = 'https://***************.ingest.monitor.azure.com'
$DcrImmutableId = 'dcr-*********************'
$Table = '*********_CL'

$TimeGenerated = Get-Date -Format "yyyy-MM-dd hh:mm:ss"

$body = Invoke-RestMethod -Headers @{"Metadata"="true"} -Method GET -Uri "http://169.254.169.254/metadata/scheduledevents?api-version=2020-07-01" 
$body | Add-Member TimeGenerated $TimeGenerated
$body | Add-Member Hostname $Env:Computername
$requestBody = @($body)
$requestBody = $requestBody | ConvertTo-Json -Depth 4 -AsArray

# Get an access token for managed identities for Azure resources
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmonitor.azure.com%2F' -Headers @{Metadata="true"}
$content =$response.Content | ConvertFrom-Json
$access_token = $content.access_token

$headers = @{"Authorization" = "Bearer $access_token"; "Content-Type" = "application/json" };
$uri = "$DceURI/dataCollectionRules/$DcrImmutableId/streams/Custom-$Table"+"?api-version=2021-11-01-preview";
$uploadResponse = Invoke-RestMethod -Uri $uri -Method "Post" -Body $requestBody -Headers $headers;

$DceURI にはData Collection Endpoint リソースのログ インジェストの値を設定します
$DcrImmutableId にはData Collection Rule リソース をJSONビュー で表示したときに確認できるproperties.immutableId の値を設定します
$Table には作成したカスタムログテーブルのテーブル名を設定します

※前項のJSONのプロパティを変更した場合、それに合わせてこのpowershell を修正します

  1. VM にタスクスケジューラーを設定してpowershell を定期実行する
    定期実行するためにログオフしているときも実行されるように注意

VMの設定をまとめてAzureから行う

powershell の配置とタスクスケジューラーの設定をAzureから行う方法

new-item -Path C:\tmp -Type directory
https://github.com/PowerShell/PowerShell/releases/download/v7.3.3/PowerShell-7.3.3-win-x86.msi -OutFile C:\tmp\PowerShell-7.3.3-win-x86.msi
msiexec.exe /package C:\tmp\PowerShell-7.3.3-win-x86.msi /quiet ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 ENABLE_PSREMOTING=1 REGISTER_MANIFEST=1 USE_MU=1 ENABLE_MU=1 ADD_PATH=1

# polling scheduled event script here document
Set-Content -Path "C:\tmp\scheduledevents.ps1" -Force -Value @'
Invoke-WebRequest -Uri 
Add-Type -AssemblyName System.Web
$DceURI = 'https://**************.ingest.monitor.azure.com'
$DcrImmutableId = 'dcr-**************'
$Table = '**************_CL'

$TimeGenerated = Get-Date -Format "yyyy-MM-dd hh:mm:ss"

$body = Invoke-RestMethod -Headers @{"Metadata"="true"} -Method GET -Uri "http://169.254.169.254/metadata/scheduledevents?api-version=2020-07-01" 
$body | Add-Member TimeGenerated $TimeGenerated
$body | Add-Member Hostname $Env:Computername
$requestBody = @($body)
$requestBody = $requestBody | ConvertTo-Json -Depth 4 -AsArray

# Get an access token for managed identities for Azure resources
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmonitor.azure.com%2F' -Headers @{Metadata="true"}
$content =$response.Content | ConvertFrom-Json
$access_token = $content.access_token

$headers = @{"Authorization" = "Bearer $access_token"; "Content-Type" = "application/json" };
$uri = "$DceURI/dataCollectionRules/$DcrImmutableId/streams/Custom-$Table"+"?api-version=2021-11-01-preview";
$uploadResponse = Invoke-RestMethod -Uri $uri -Method "Post" -Body $requestBody -Headers $headers;
'@

# Set Task Scheduler
$Trigger = New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 1) -Once -At (Get-Date)
$Action = New-ScheduledTaskAction -Execute "C:\Program Files (x86)\PowerShell\7\pwsh" -Argument ".\scheduledevents.ps1 -ExecutionPolicy Bypass" -WorkingDirectory "C:\tmp"
$Settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 1) -StartWhenAvailable
$STPrin = New-ScheduledTaskPrincipal -LogonType S4U -UserID "SYSTEM"
Register-ScheduledTask -TaskName "Polling Scheduled events of Azure Platform" -Action $Action -Trigger $Trigger -Settings $Settings -Principal $STPrin

PowerShell7をインストールし、ヒアドキュメントで powershell スクリプトを C:\tmp に保存し、保存したスクリプトをタスクスケジューラーで定期実行させるスクリプトです。
このスクリプトを polling.ps1 としてAzure CLI が使える端末に保存し

az vm run-command invoke --command-id RunPowerShellScript --name {vmName} -g {resourceGroupName} --scripts @polling.ps1

上記コマンドを実行することでVMにログインせずに設定を完了できます。

Microsoft (有志)

Discussion