はじめに
Azure上でのWindows Update管理、ちょっと面倒に感じていませんか?
そこで今回は、Azure環境でWindows Updateを自動化できるPowerShellスクリプトを
紹介します。
このスクリプトを作成したのは、Automation Update Managementから
Azure Update Managerへの切り替えが必要になったことがきっかけです。
同じようにAutomation Update Managementからの切り替えに
悩んでいる人に届けば幸いです。
この記事で得られること
Azure VMのWindows Updateを完全自動化するスクリプトの詳細
定期実行のスケジュール設定方法
自動化に伴うトラブルシューティング
こんな人におすすめ
Azure環境の仮想マシンを効率よく管理したい方
手動でのWindows Updateに手間を感じているシステム管理者
PowerShellスクリプトを活用して自動化を学びたい方
スクリプトの概要
今回紹介するスクリプトでは、以下の機能を実現します。
1. Azure VMのWindows Updateを定期的に実行
2. 再起動のスケジュール設定(任意の時間に再起動をスケジュール可能)
3. Updateにかかる時間を指定
これにより日々のメンテナンス作業を自動化し、ヒューマンエラーのリスクを最小限に抑えます。
対象環境
実際に確認した環境は以下の通りです。
OS | VM サイズ |
---|---|
W2012R2,W2016,W2019,W2022 | Standard_A4_v2, Standard_B2ms, Standard_D2ds_v4, Standard_D2ds_v5, Standard_D2s_v3, Standard_D4ds_v4, Standard_D4ds_v5, Standard_D4s_v3, Standard_D8ds_v5, Standard_DS11_v2, Standard_DS12_v2, Standard_DS2_v2, Standard_DS3_v2, Standard_DS4_v2, Standard_E2ds_v4, Standard_E2ds_v5, Standard_E2s_v3, Standard_E2s_v5, Standard_E4ds_v4, Standard_E4ds_v5, Standard_E4s_v3, Standard_E8ds_v5, Standard_E8s_v3, Standard_GS1 |
スクリプトの内容と導入手順
1. 事前準備
〇必要な環境
- Azure仮想マシン(Windows Server)
- Azure PowerShellモジュールをインストール済みであること
PowerShellモジュールのインストール
まずはPowerShellのAzureモジュールをインストールしてください。
Install-Module -Name Az -AllowClobber -Force
他のモジュールが必要になる可能性もありますが、エラーに応じて
必要なモジュールを調べてインストールしてください。
更新プログラムの確認
VM→更新プログラムをクリックすると更新可能なプログラム名が表示されます。
適用するパッチを指定する場合は、この画面で表示されたKB番号を指定してください
※ここに表示されていないパッチは、スクリプトで指定してもパッチが適用されません
2. スクリプトの解説
以下がWindows Updateを自動化するPowerShellスクリプトです。
このスクリプトは、Azureの仮想マシン上で決められた日時にWindows Updateを実行します。
#---------------------------
#MaintenanceName
$MaintenanceName = "XXX"
#VMを代入する
$VMname =@()
$VMname += "XXXServer"
$VMname += "XXXServer"
#時間を代入する
$startTime = "2024-XX-XX 04:30"
$updateTime = "2024-XX-XX 02:00"
$stopTime = "2024-XX-XX 04:15"
$ExpirationDateTime = "2024-XX-XX 04:00"
#サブスクリプションID
$SubscriptionId = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
#リソースグループ名
$ResourceGroupName = "XXXXX"
#AutomationAccount名
$AutomationName = "XXXXXXX"
#OS種別19
$VMOS =@()
$VMOS += "W2016"
$VMOS += "W2022"
#対象VM
$targetMachine =@()
for($i=0; $i -lt $VMname.Length; $i++){
$NM = $VMname[$i]
$targetMachine += "/subscriptions/${SubscriptionId}/resourceGroups/${ResourceGroupName}/providers/Microsoft.Compute/virtualMachines/${NM}"
}
#AzMaintenanceConfigurationに必要なパラメータ
$scope = "InGuestPatch"
$location = "japaneast"
$timeZone = "Tokyo Standard Time"
$duration = "02:00"
$recurEvery = "1Day"
$RebootOption = "IfRequired";
#---------------------------
#チェック用の変数
$ck_up = 0
$ck_down = 0
#Runbook名の変数
$Runbook = 'XXXX'
#起動停止のスケジュールが無い場合のメッセージ
$msg_up = "WinUp起動のスケジュール設定がなかったので設定しました"
$msg_down = "WinUp停止のスケジュール設定がなかったので設定しました"
#Azureに接続
Connect-AzAccount
Set-AzContext $SubscriptionId
$Item = Get-AzAutomationSchedule -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationName
for($i=0; $i -lt $Item.Length; $i++){
$AutoName = $Item[$i].Name.ToLower()
if($AutoName -eq "winup起動"){
#WinUp起動設定
New-AzAutomationSchedule `
-AutomationAccountName $AutomationName `
-Name $AutoName `
-StartTime $startTime `
-OneTime `
-ResourceGroupName $ResourceGroupName `
-TimeZone $timeZone
$ck_up++
}elseif($AutoName -eq "winup停止"){
#WinUp停止設定
New-AzAutomationSchedule `
-AutomationAccountName $AutomationName `
-Name $AutoName `
-StartTime $stopTime `
-OneTime `
-ResourceGroupName $ResourceGroupName `
-TimeZone $timeZone
$ck_down++
}else{
}
}
if($ck_up -eq 0){
#WinUp起動新規作成
New-AzAutomationSchedule `
-AutomationAccountName $AutomationName `
-Name "WinUp起動" `
-StartTime $startTime `
-OneTime `
-ResourceGroupName $ResourceGroupName `
-TimeZone $timeZone
#起動スケジュールとRunbookを紐付ける
$StartParams = @{"Action" = "START";"ResourceGroupName" = $ResourceGroupName}
Register-AzAutomationScheduledRunbook -AutomationAccountName $AutomationName -RunbookName $Runbook -ScheduleName "WinUp起動" -ResourceGroupName $ResourceGroupName -Parameters $StartParams
}
if($ck_down -eq 0){
#WinUp停止新規作成
New-AzAutomationSchedule `
-AutomationAccountName $AutomationName `
-Name "WinUp停止" `
-StartTime $stopTime `
-OneTime `
-ResourceGroupName $ResourceGroupName `
-TimeZone $timeZone
#停止スケジュールとRunbookを紐付ける
$StopParams = @{"Action" = "STOP";"ResourceGroupName" = $ResourceGroupName}
Register-AzAutomationScheduledRunbook -AutomationAccountName $AutomationName -RunbookName $Runbook -ScheduleName "WinUp停止" -ResourceGroupName $ResourceGroupName -Parameters $StopParams
}
#旧WindowsUpdate削除
$UpdateSet = Get-AzAutomationSoftwareUpdateConfiguration -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationName
for($i=0; $i -lt $UpdateSet.Length; $i++){
$UpdateName = $UpdateSet[$i].Name
$UpdateName
Remove-AzAutomationSoftwareUpdateConfiguration -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationName -Name $UpdateName
}
#WindowsUpdate設定
for($i=0; $i -lt $VMname.Length; $i++){
$NM = $VMname[$i]
$KB = ""
#OSごとのKB番号を連想配列で定義する
$KBMap = @{
"W2012R2" = @(5041XXX, 5041XXX)
"W2016" = @(5041XXX, 5041XXX)
"W2019" = @(5041XXX)
"W2022" = @(5041XXX)
}
# OSの種類に基づいてKB番号を取得
$KB = $KBMap[$VMOS[$i]]
#パッチオーケストレーションをCustomer Managed Schedulesに変更
$VirtualMachine = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMname[$i]
Set-AzVMOperatingSystem -VM $VirtualMachine -PatchMode "AutomaticByPlatform"
$AutomaticByPlatformSettings = $VirtualMachine.OSProfile.WindowsConfiguration.PatchSettings.AutomaticByPlatformSettings
if ($null -eq $AutomaticByPlatformSettings) {
$VirtualMachine.OSProfile.WindowsConfiguration.PatchSettings.AutomaticByPlatformSettings = New-Object -TypeName Microsoft.Azure.Management.Compute.Models.WindowsVMGuestPatchAutomaticByPlatformSettings -Property @{BypassPlatformSafetyChecksOnUserSchedule = $true}
}else {
$AutomaticByPlatformSettings.BypassPlatformSafetyChecksOnUserSchedule = $true
}
Update-AzVM -VM $VirtualMachine -ResourceGroupName $ResourceGroupName
#Update用のメンテナンス構成を作成
$config = New-AzMaintenanceConfiguration `
-ResourceGroup $ResourceGroupName `
-Name "${MaintenanceName}_${NM}" `
-MaintenanceScope $scope `
-Location $location `
-StartDateTime $updateTime `
-ExpirationDateTime $stopTime `
-TimeZone $timeZone `
-Duration $duration `
-RecurEvery $recurEvery `
-WindowParameterKbNumberToInclude $KB `
-InstallPatchRebootSetting $RebootOption `
-ExtensionProperty @{"InGuestPatchMode"="User"}
Get-AzMaintenanceConfiguration | Format-Table -Property Name,Id
#作成したメンテナンス構成を各VMと紐づける
New-AzConfigurationAssignment `
-ResourceGroupName $ResourceGroupName `
-Location $location `
-ResourceName $VMname[$i] `
-FilterOsType Windows `
-ResourceType VirtualMachines `
-ProviderName Microsoft.Compute `
-ConfigurationAssignmentName $config.Name `
-MaintenanceConfigurationId $config.Id
}
Disconnect-AzAccount
if($ck_up -eq 0){
$msg_up
}
if($ck_down -eq 0){
$msg_down
}
PAUSE
スクリプトのポイント
①#--に囲まれた変数を変更するだけで、様々なVM台数、OSVerでも適用が可能。
②VM種別に応じたKBパッチを適用することが出来る。
③Automationスケジュールによって、Windows Updateの時間に合わせて
VMを起動・停止を行うことが出来る
スクリプト実行後のAzure側の動作
①VMを起動させる
→スクリプトで設定した、Automationの「WinUP起動」にて実施
②設定した時間にUpdateを実施する
→設定した時間内で実施、この時適用されるパッチは事前に設定したもの
③VMを停止する
→スクリプトで設定した、Automationの「WinUP停止」にて実施
スクリプト実行の流れ
①PowerShell ISEでスクリプトを実行します。
②スクリプトを実行するMicrosoftアカウントにログインします
③下記のメッセージが流れればスクリプトの実行は完了です。
・WinUp起動のスケジュール設定がなかったので設定しました
・WinUp停止のスケジュール設定がなかったので設定しました
・続行するには、Enter キーを押してください...:
実行ウィンドウを上にスクロールしていくと色々書いていますが、
エラーがなければ実行完了です。
実行結果と実行後の適用確認
- VMの更新プログラムの中に適用したいパッチが入っていること
(事前に確認していると思いますが、最終確認も兼ねて確認することをお勧めします)
まとめ
このスクリプトを導入することで、Azure上でのWindows Updateを自動化することが
可能です。VM台数分、VMそれぞれの設定値に合わせて設定することが出来るので、
多数の仮想マシンを管理する際には、効率化が期待できます。
複数サブスクリプションに適用したい場合は、
それぞれのサブスクリプションに合わせたパラメータを使用してください。
(複数環境を作成するためにパラメータ作成シート等があると便利です)
おわりに
この記事が役に立った場合は「いいね」や「フォロー」をしていただけると励みになります。また、質問やフィードバックはコメント欄でお待ちしています。
おまけ
試してないけど出来そうなこと
・1度スクリプトを実行すれば、1か月置きや半年置きなどスクリプトを実行しなくても
WindowsUpdateを実行すること
→スケジュールを1dayから変更すれば可能なはず。公式ドキュメントによると
日、週、月単位でスケジュール設定が可能っぽい
参考↓
$recurEvery = "2Months"
・パッチを指定せずにスクリプトを実行する
→空白(または該当行を削除)にすることで出来るはず
参考↓
-WindowParameterKbNumberToInclude `
・1つのメンテナンス構成に2つのVMを設定すること
→当社では1環境あたりに複数VMが存在し、かつOSが違う(=適用パッチが違う)ことも
あることから、VM台数分のメンテナンス構成を作成するスクリプトになっているが
1環境のVMが同じで、適用パッチも同じであれば、1つのメンテナンス構成にまとめられる
はず
参考↓(恐らくこれだと複数OS選択時は、すべてのOSに対するKBパッチが集約されるはず)
$allKB = @()
for($i=0; $i -lt $VMname.Length; $i++){
$NM = $VMname[$i]
$KB = ""
$KBMap = @{
"W2012R2" = @(5041XXX, 5041XXX)
"W2016" = @(5041XXX, 5041XXX)
"W2019" = @(5041XXX)
"W2022" = @(5041XXX)
}
$KB = $KBMap[$VMOS[$i]]
$allKB += $KB
}
※あくまで参考です。使う際は必ずテストを行ってください