弊社で一般職、管理職向けにVDIとしてWVDを導入する動きがあってその運用管理の手伝いをすることになりました。
真っ先に私のタスクになったのはVMの節約
調べると
https://docs.microsoft.com/ja-jp/azure/automation/automation-solution-vm-management
とか
https://365cloud.jp/wvd%E3%82%92%E6%A5%AD%E5%8B%99%E6%99%82%E9%96%93%E4%B8%AD%E3%81%AE%E3%81%BF%E8%B5%B7%E5%8B%95%E3%81%95%E3%81%9B%E3%82%8B%EF%BC%88%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E8%87%AA/
とか
出てきたのでこれは楽勝と思っていたのですが、
実行するとこんなエラーが
Add-AzureRmMetricAlertRule : Exception type: ErrorResponseException, Message: You cannot create or modify classic metric alerts for this subscription as this subscription X-x-x-x-x is being migrated or has been migrated to use new metric alerts. Learn more - aka.ms/alertclassicretirement, Code: BadRequest, Status code:BadRequest, Reason phrase: Bad Request At line:192 char:34 + ... Add-AzureRmMetricAlertRule -Name $NewAlertName ` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [Add-AzureRmMetricAlertRule], PSInvalidOperationException + FullyQualifiedErrorId : Microsoft.Azure.Commands.Insights.Alerts.AddAzureRmMetricAlertRuleCommand
昨年クラシックアラートが廃止になった影響がでました。
上で紹介した公式ページの説明だと
私が着手したの3月入ってから、目と鼻の差で実現不可能に、
しかし、最新のAzモジュールに差し替えて、Poweshellも書き換えれば実行できるはず
ということでいろいろ調べましたが、結局公式のAzurePowershellのリファレンスを読み漁ってトライ&エラーで設定したので差し替えたスクリプトを残しておこうと思います。
今回はWVDのVMの節約のために導入しましたが、通常のVMの節約でも使用できるので、興味がある方は設定してみてください。
また、2020年3月18日時点の情報ですので、今後該当のソリューションが更新された場合は動作の保証はできませんのでご了承ください。
手順
まずは
Azure Automation でのピーク時間外 VM 起動/停止ソリューション
の作業を行います。
必要に応じて
365クラウドの記事の設定に変更してもOKです。
変更点1
通常の状態の設定が完了した後は、
まず、Azモジュールを追加します。
Az モジュールをインポートする
を参考にして、
追加するモジュールは
Az.Accounts
Az.Automation
Az.Compute
Az.Monitor
Az.Resources
だけです。
変更点2
使用するRUNBOOKのxx-AzureRMxxをxx-Azxxに書き換えてパブリッシュします。
私が使用したのは365クラウドの記事を参考にしたので定時起動、夜使用していなかったら停止かつクラシックは必要ないので、
定時起動用の
ScheduledStartStop_Parent
ScheduledStartStop_Child
と
使用していなかったら停止用の
AutoStop_CreateAlert_Parent
AutoStop_CreateAlert_Child
AutoStop_VM_Child
のRUNBOOKを変更しました。
変更点3
そして今回の修正の肝となるクラシックアラートの廃止の部分を変更します。
対象RUNBOOKは、
AutoStop_CreateAlert_Child
です。
param(
$VMObject,
[string]$AlertAction,
[string]$WebhookUri
)
#-----Function to generate unique alert name-----
function Generate-AlertName
{
param (
[string] $OldAlertName ,
[string] $VMName
)
[string[]] $AlertSplit = $OldAlertName -split "-"
[int] $Number =$AlertSplit[$AlertSplit.Length-1]
$Number++
$Newalertname = "Alert-$($VMName)-$Number"
return $Newalertname
}
# ------------------Execution Entry point ---------------------
[string] $FailureMessage = "Failed to execute the command"
[int] $RetryCount = 3
[int] $TimeoutInSecs = 20
$RetryFlag = $true
$Attempt = 1
do
{
Write-Output "Logging into Azure subscription using Az cmdlets..."
#-----L O G I N - A U T H E N T I C A T I O N-----
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
Add-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
Write-Output "Successfully logged into Azure subscription using Az cmdlets..."
$RetryFlag = $false
}
catch
{
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
$RetryFlag = $false
throw $ErrorMessage
}
if ($Attempt -gt $RetryCount)
{
Write-Output "$FailureMessage! Total retry attempts: $RetryCount"
Write-Output "[Error Message] $($_.exception.message) `n"
$RetryFlag = $false
}
else
{
Write-Output "[$Attempt/$RetryCount] $FailureMessage. Retrying in $TimeoutInSecs seconds..."
Start-Sleep -Seconds $TimeoutInSecs
$Attempt = $Attempt + 1
}
}
}
while($RetryFlag)
#---------Read all the input variables---------------
$SubId = Get-AutomationVariable -Name 'Internal_AzureSubscriptionId'
#-----Prepare the inputs for alert attributes-----
$threshold = Get-AutomationVariable -Name 'External_AutoStop_Threshold'
$metricName = Get-AutomationVariable -Name 'External_AutoStop_MetricName'
$timeWindow = Get-AutomationVariable -Name 'External_AutoStop_TimeWindow'
$condition = Get-AutomationVariable -Name 'External_AutoStop_Condition' # Other valid values are LessThanOrEqual, GreaterThan, GreaterThanOrEqual
$description = Get-AutomationVariable -Name 'External_AutoStop_Description'
$timeAggregationOperator = Get-AutomationVariable -Name 'External_AutoStop_TimeAggregationOperator'
$webhookUri = Get-AutomationVariable -Name 'Internal_AutoSnooze_WebhookUri'
try
{
Write-Output "Runbook execution started..."
$ResourceGroupName =$VMObject.ResourceGroupName
$Location = $VMObject.Location
Write-Output "Location...$($VMObject.Location)"
Write-Output "getting status..."
$VMState = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMObject.Name -Status -ErrorAction SilentlyContinue).Statuses.Code[1]
$resourceId = "/subscriptions/$($SubId)/resourceGroups/$ResourceGroupName/providers/Microsoft.Compute/virtualMachines/$($VMObject.Name.Trim())"
Write-Output "Processing VM ($($VMObject.Name))"
Write-Output "Current VM state is ($($VMState))"
####変更箇所
#$actionWebhook = New-AzAlertRuleWebhook -ServiceUri $WebhookUri
$actionWebhook = Get-AzActionGroup -Name "WebHookToAutomation" -ResourceGroupName $ResourceGroupName
if($null -eq $act ){
$webhookReceiver = New-AzActionGroupReceiver -Name 'webhookReceiver' -WebhookReceiver -ServiceUri $WebhookUri
$actionWebhook = Set-AzActionGroup -Name "WebHookToAutomation" -ResourceGroupName $ResourceGroupName -ShortName "Hook" -Receiver $webhookReceiver
}
$Criteria = New-AzMetricAlertRuleV2Criteria -MetricName $metricName -TimeAggregation $timeAggregationOperator -Operator $condition -Threshold $threshold
####変更箇所
$NewAlertName ="Alert-$($VMObject.Name)-1"
if($AlertAction -eq "Disable")
{
####変更箇所
$ExVMAlerts = Get-AzMetricAlertRuleV2 -ResourceGroup $VMObject.ResourceGroupName -ErrorAction SilentlyContinue
####変更箇所
if($ExVMAlerts -ne $null)
{
Write-Output "Checking for any previous alert(s)..."
#Alerts exists so disable alert
foreach($Alert in $ExVMAlerts)
{
if($Alert.Name.ToLower().Contains($($VMObject.Name.ToLower().Trim())))
{
Write-Output "Previous alert ($($Alert.Name)) found and disabling now..."
####変更箇所
Add-AzMetricAlertRuleV2 `
-Name $Alert.Name `
-ResourceGroupName $ResourceGroupName `
-WindowSize $timeWindow `
-Frequency $timeWindow `
-TargetResourceScope $resourceId `
-TargetResourceType "Microsoft.Compute/virtualMachines" `
-TargetResourceRegion $Alert.Location `
-Description $description `
-Severity 4 `
-ActionGroupId $actionWebhook.Id `
-Condition $Criteria -DisableRule
####変更箇所
Write-Output "Alert ($($Alert.Name)) Disabled for VM $($VMObject.Name)"
}
}
}
}
elseif($AlertAction -eq "Create")
{
#Getting ResourcegroupName and Location based on VM
if (($VMState -eq 'PowerState/running') -or ($VMState -eq 'ReadyRole'))
{
try
{
Write-Output "Creating alerts..."
####変更箇所
$VMAlerts = Get-AzMetricAlertRuleV2 -ResourceGroup $ResourceGroupName -ErrorAction SilentlyContinue
####変更箇所
#Check if alerts exists and take action
if($VMAlerts -ne $null)
{
Write-Output "Checking for any previous alert(s)..."
#Alerts exists so delete and re-create the new alert
foreach($Alert in $VMAlerts)
{
if($Alert.Name.ToLower().Contains($($VMObject.Name.ToLower().Trim())))
{
Write-Output "Previous alert ($($Alert.Name)) found and deleting now..."
#Remove the old alert
####変更箇所
Remove-AzMetricAlertRuleV2 -Name $Alert.Name -ResourceGroup $ResourceGroupName
####変更箇所
#Wait for few seconds to make sure it processed
Do
{
#Start-Sleep 10
####変更箇所
$GetAlert=Get-AzMetricAlertRuleV2 -ResourceGroup $ResourceGroupName -Name $Alert.Name -ErrorAction SilentlyContinue
####変更箇所
}
while($GetAlert -ne $null)
Write-Output "Generating a new alert with unique name..."
#Now generate new unique alert name
$NewAlertName = Generate-AlertName -OldAlertName $Alert.Name -VMName $VMObject.Name
}
}
}
#Alert does not exist, so create new alert
Write-Output $NewAlertName
Write-Output "Adding a new alert to the VM..."
####変更箇所
Add-AzMetricAlertRuleV2 `
-Name $NewAlertName `
-ResourceGroupName $ResourceGroupName `
-WindowSize $timeWindow `
-Frequency $timeWindow `
-TargetResourceScope $resourceId `
-TargetResourceType "Microsoft.Compute/virtualMachines" `
-TargetResourceRegion $location `
-Description $description `
-Severity 4 `
-ActionGroupId $actionWebhook.Id `
-Condition $Criteria
####変更箇所
Write-Output "Alert Created for VM $($VMObject.Name.Trim())"
}
catch
{
Write-Output "Error Occurred"
Write-Output $_.Exception
}
}
else
{
Write-Output " $($VM.Name) is De-allocated"
}
}
}
catch
{
Write-Output "Error Occurred"
Write-Output $_.Exception
}
以上が変更点です。