I put my Azure Update Management into full testing recently, using the deployment script I shared last week.
I quickly encountered a problem where despite the VMs communicating with Azure Automation properly, and showing as “ready” for Update Management, they would no longer appear as selected when using Dynamic Groups.
I suspect this may have something to do with the proxy setup in this particular environment, but I didn’t have time to troubleshoot and needed to have my scheduled update configurations statically select my VMs instead of relying upon dynamic groups (they are after all still in preview).
However, I still wanted to use Tags in order to select my VMs. In order to do this, I removed the “Targets” object from my JSON body entirely, and used the “azureVirtualMachines” object instead. I needed to put the logic of VM selection based on tags into this object.
I recognize that this removes the “dynamic” nature, in that it would only be updated when I re-run the PowerShell script to update the scheduled update configuration, but since this is going to be run once-per-month in order to change the date (Microsoft, add day offset support!) that isn’t a large problem.
The only real change is that selection of the VMs by tag can be done like this:
$selectedvms = Get-AzureRmVM | Where-Object {$_.Tags['MaintenanceWindow'] -eq $MaintenanceWindow} | select-object id
$virtualmachines = $selectedvms.id | ConvertTo-JSON
Multiple Tag definitions can be added into the “Where-Object” logic of that command.
Full Example
# API Reference: https://docs.microsoft.com/en-us/rest/api/automation/softwareupdateconfigurations/create#updateconfiguration
### Monthly Parameters ###
$deploymentName = "SUG_Thurs-2am-MST-4hours"
$MaintenanceWindow = "Thurs-2am-MST-4hours"
$starttime = "2018-11-15T02:00:00+00:00"
# Scope Parameters
$clientsubscription = ""
Select-AzureRmSubscription -Subscription $clientsubscription
## Schedule Parameters
# Populate an array with the full ID of all VMs to apply this schedule to:
$selectedvms = Get-AzureRmVM | Where-Object {$_.Tags['MaintenanceWindow'] -eq $MaintenanceWindow} | select-object id
$virtualmachines = $selectedvms.id | ConvertTo-JSON
# Static Schedule Parameters
$AutomationRG = "test-rg" # Resource Group the Automation Account resides in
$automationAccountName = "test-automation"
$automationSubscription = "" # Subscription that the Automation Account resides in
$duration = "PT4H0M" # This equals maintenance window - Put in the format PT2H0M, changing the numbers for hours and minutes
$rebootSetting = "IfRequired" # Options are Never, IfRequired
$includedUpdateClassifications = "Critical,UpdateRollup,Security,Updates" # List of options here: https://docs.microsoft.com/en-us/rest/api/automation/softwareupdateconfigurations/create#windowsupdateclasses
$timeZone = "America/Edmonton" # List from ??
$frequency = "OneTime" # Valid values: https://docs.microsoft.com/en-us/rest/api/automation/softwareupdateconfigurations/create#schedulefrequency
#$interval = "1" # How often to recur based on the frequency (i.e. if frequency = hourly, and interval = 2, then its every 2 hours)
### These values below shouldn't need to change
Select-AzureRmSubscription -Subscription "$automationSubscription"
# Get the access token from a cached PowerShell session
. .\Get-AzureRmCachedAccessToken.ps1 # Source = https://gallery.technet.microsoft.com/scriptcenter/Easily-obtain-AccessToken-3ba6e593
$BearerToken = ('Bearer {0}' -f (Get-AzureRmCachedAccessToken))
$RequestHeader = @{
"Content-Type" = "application/json";
"Authorization" = "$BearerToken"
}
# JSON formatting to define our required settings
$Body = @"
{
"properties": {
"updateConfiguration": {
"operatingSystem": "Windows",
"duration": "$duration",
"windows": {
"excludedKbNumbers": [],
"includedUpdateClassifications": "$includedUpdateClassifications",
"rebootSetting": "$rebootSetting"
},
"azureVirtualMachines": $virtualmachines,
},
"scheduleInfo": {
"frequency": "$frequency",
"startTime": "$starttime",
"timeZone": "$timeZone",
"interval": $interval,
"isEnabled": true
}
}
}
"@
# Build the URI string to call with a PUT
$URI = "https://management.azure.com/subscriptions/$($automationSubscription)/" `
+"resourceGroups/$($AutomationRG)/providers/Microsoft.Automation/" `
+"automationAccounts/$($automationaccountname)/softwareUpdateConfigurations/$($deploymentName)?api-version=2017-05-15-preview"
# use the API to add the deployment
$Response = Invoke-RestMethod -Uri $URI -Method Put -body $body -header $RequestHeader
Thanks for this. I only wish Microsoft would give such detailed documentation :/