Home / Azure

AzureTroubleshootingIntermediate

Azure Update Manager: machines not assessed, patch installs failing and schedules that never run

Find why Azure Update Manager shows no assessment, failed installs or skipped maintenance runs, then fix patch mode, the agent, update sources and schedule assignments.

Deepak Bhardwaj8 min read

Applies toAzure Update Manager, Azure VMs (Windows Server and Linux), Azure Arc-enabled servers, Azure CLI 2.60+

The patch compliance report is wrong. Some machines say "No assessment", some show the last install as Failed, and some were in a maintenance window last night but nothing ran. This guide sorts those three symptoms into causes and fixes, in the order that finds the problem fastest.

Symptom to cause

Symptom Most likely cause Fix
"No updates data" or assessment is days old Periodic assessment off, VM agent not ready, machine deallocated Set assessmentMode to AutomaticByPlatform, fix the agent
Assessment fails immediately Windows Update service disabled, WSUS policy pointing to a dead server, Linux repo unreachable Fix the update source on the guest
Install shows Failed or partial Maintenance window too short, reboot blocked, package manager locked Raise --maximum-duration, check guest logs
Schedule ran but machine skipped Patch orchestration not set to AutomaticByPlatform with the safety check bypass Set both properties
Schedule never touched the machine No maintenance configuration assignment, or the dynamic scope filter doesn't match Check assignments and scope tags
Arc server shows nothing Arc agent disconnected or resource provider not registered Reconnect agent, register providers

Check 1: find the affected machines with Resource Graph

Start from the fleet view, not the portal blade for one VM. Resource Graph holds the latest assessment and installation results.

patchassessmentresources
| where type =~ "microsoft.compute/virtualmachines/patchassessmentresults"
    or type =~ "microsoft.hybridcompute/machines/patchassessmentresults"
| extend vmId = tolower(tostring(split(id, "/patchAssessmentResults/")[0]))
| extend status = tostring(properties.status),
         lastRun = todatetime(properties.lastModifiedDateTime),
         osType = tostring(properties.osType)
| where status != "Succeeded" or lastRun < ago(2d)
| project vmId, osType, status, lastRun
| order by lastRun asc

Run it from the CLI so you can save the output for the ticket:

az graph query -q "patchassessmentresources | where type =~ 'microsoft.compute/virtualmachines/patchassessmentresults' | extend status=tostring(properties.status), lastRun=todatetime(properties.lastModifiedDateTime) | where status != 'Succeeded' or lastRun < ago(2d) | project id, status, lastRun" --first 500 -o table

For failed installs, query patchinstallationresources:

patchinstallationresources
| where type endswith "/patchinstallationresults"
| extend status = tostring(properties.status),
         started = todatetime(properties.startDateTime),
         failed = toint(properties.failedPatchCount),
         installed = toint(properties.installedPatchCount)
| where started > ago(7d) and status != "Succeeded"
| project id, status, started, installed, failed
| order by started desc

Tip

Property names inside properties have changed between API versions. If a column comes back empty, run patchinstallationresources | take 1 and read the raw JSON to get the names your tenant returns.

Check 2: patch orchestration and assessment settings

Scheduled patching only touches Azure VMs whose patch mode is AutomaticByPlatform and that have bypassPlatformSafetyChecksOnUserSchedule set to true. If the bypass is true but no schedule is assigned, the machine is never patched at all. That combination quietly causes a lot of these reports.

Read the current settings:

az vm show -g rg-prod -n vm-app01 \
  --query "{win:osProfile.windowsConfiguration.patchSettings, linux:osProfile.linuxConfiguration.patchSettings}" -o json

Set them on a Windows VM:

az vm update -g rg-prod -n vm-app01 \
  --set osProfile.windowsConfiguration.patchSettings.patchMode=AutomaticByPlatform \
        osProfile.windowsConfiguration.patchSettings.assessmentMode=AutomaticByPlatform \
        osProfile.windowsConfiguration.patchSettings.automaticByPlatformSettings.bypassPlatformSafetyChecksOnUserSchedule=true

On Linux, use the same keys under osProfile.linuxConfiguration.patchSettings.

Warning

Some Azure CLI releases after 2.78 have reported problems setting the bypass flag with az vm update. If the command errors or the value doesn't stick, set it in the portal (Update Manager > Settings > Update settings) or through the built-in Azure Policy that configures periodic assessment and patch orchestration. Then confirm with az vm show.

assessmentMode=AutomaticByPlatform turns on periodic assessment, which runs about every 24 hours. Without it, you only see data when someone clicks "Check for updates".

Check 3: the VM agent and the patch extension

Update Manager runs through the Azure VM agent and an extension it installs on demand (WindowsPatchExtension or LinuxPatchExtension, publisher Microsoft.CPlat.Core).

az vm get-instance-view -g rg-prod -n vm-app01 \
  --query "{power:instanceView.statuses[1].displayStatus, agent:instanceView.vmAgent.statuses[0].displayStatus, ext:instanceView.extensions[].{name:name, status:statuses[0].displayStatus}}" -o json

The agent must be Ready and the VM must be running. A deallocated VM is skipped by both assessment and maintenance runs; that is expected, not an error.

Read the extension logs without logging in, using Run Command:

# Windows
az vm run-command invoke -g rg-prod -n vm-app01 --command-id RunPowerShellScript \
  --scripts "Get-ChildItem C:\WindowsAzure\Logs\Plugins\Microsoft.CPlat.Core.WindowsPatchExtension -Recurse -Filter *.log | Sort-Object LastWriteTime | Select-Object -Last 1 | Get-Content -Tail 60"

# Linux
az vm run-command invoke -g rg-prod -n vm-lnx01 --command-id RunShellScript \
  --scripts "ls -t /var/log/azure/Microsoft.CPlat.Core.LinuxPatchExtension/ && tail -n 60 /var/log/azure/Microsoft.CPlat.Core.LinuxPatchExtension/*.log"

Log folder names can carry a version suffix on some builds, so list the parent folder first if the path doesn't exist.

Check 4: the update source inside the guest

Most assessment failures are a broken update source, not an Update Manager fault.

Windows

Get-Service wuauserv, bits | Select-Object Name, Status, StartType
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v WUServer
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v UseWUServer
  • wuauserv start type Disabled (often set by a hardening GPO) makes every assessment fail. Set it to Manual.
  • If UseWUServer is 1, the machine asks the WSUS server in WUServer. If that server is retired or unreachable, assessment fails. Fix the GPO, don't change the registry by hand; Group Policy writes it back.
  • With no WSUS, the VM needs outbound HTTPS to Windows Update endpoints. A VM in a subnet with no outbound path (see the default outbound access retirement) can't reach them.

Linux

sudo apt-get update            # Debian/Ubuntu
sudo dnf check-update || true  # RHEL/Alma/Rocky (exit code 100 means updates exist)
sudo zypper refresh            # SLES

Look for repository errors, expired GPG keys, or a lock held by unattended-upgrades or another package process. A stuck dpkg lock makes the install fail with a timeout.

Check 5: schedules and assignments

If assessment is healthy but the maintenance run skipped the machine, check the assignment:

az maintenance assignment list \
  --resource-group rg-prod --resource-name vm-app01 \
  --resource-type virtualMachines --provider-name Microsoft.Compute -o table

No row means the machine isn't in the schedule. For dynamic scopes, check that the machine's subscription, resource group, location, OS type and tags actually match the filter. A tag typo (Patch-Ring vs PatchRing) is a common cause.

Look at the configuration's window too:

az maintenance configuration show -g rg-maint -n mc-ring1-sun02 \
  --query "{start:maintenanceWindow.startDateTime, duration:maintenanceWindow.duration, tz:maintenanceWindow.timeZone, recur:maintenanceWindow.recurEvery, reboot:installPatches.rebootSetting}" -o json

Update Manager stops starting new installs near the end of the window so it can reboot inside it. With a short window and a big cumulative update, the run ends with some patches not attempted.

Fix: run it once by hand

After fixing the cause, prove it with an on-demand assessment and install:

az vm assess-patches -g rg-prod -n vm-app01

az vm install-patches -g rg-prod -n vm-app01 \
  --maximum-duration PT2H --reboot-setting IfRequired \
  --classifications-to-include-win Critical Security

For Linux, use --classifications-to-include-linux Critical Security. Both commands return the status and counts, and the result appears in Resource Graph within a few minutes.

Caution

--reboot-setting IfRequired or Always will restart the VM. On a production single-instance VM, run this inside an agreed window or use NeverReboot and schedule the restart separately.

Arc-enabled servers

For Arc machines, check the Connected Machine agent first:

az connectedmachine show -g rg-hybrid -n srv-onprem01 --query "{status:status, lastSeen:lastStatusChange, agent:agentVersion}" -o table

A status of Disconnected means no assessment data. Restart the himds service on the server and confirm outbound access to the Arc endpoints. Also make sure the subscription has the Microsoft.HybridCompute and Microsoft.Compute resource providers registered (az provider show -n Microsoft.Compute --query registrationState).

Prevent it next time

  • Assign the built-in policies that enable periodic assessment and set the patch orchestration prerequisites, so new VMs are correct on day one.
  • Alert on the Resource Graph query in Check 1: any machine with no successful assessment in 48 hours.
  • Keep WSUS and proxy changes in the change calendar; retiring a WSUS server breaks assessment for every VM still pointing at it.
  • Size maintenance windows for the largest monthly update, not the average one. Leave time for the reboot.
  • After each patch cycle, review patchinstallationresources for Failed and partial runs before the next ring starts.