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 = "<subscription_id_to_target>" 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 = "<subscriptionId>" # 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 :/