The application team reports that a VM "went down for five minutes" overnight. Before anyone opens a support case, you need to answer one question: who or what restarted it? There are only four possibilities, and each one leaves evidence in a different place.
| Who restarted it | Where the evidence is | Typical signal |
|---|---|---|
| Azure platform (host repair, maintenance) | Resource Health annotations | VirtualMachineHostRebootedForRepair, planned maintenance |
| A person or pipeline through ARM | Activity Log | Microsoft.Compute/virtualMachines/restart/action with a caller |
| Automation inside Azure (Update Manager, auto-shutdown, runbooks) | Activity Log, Update Manager history | Caller is a managed identity or service principal |
The guest OS (patch reboot, crash, user shutdown) | Windows Event Log, Linux journal | Event 1074, 41, 6008, kernel panic |
Work through them in this order. The platform and ARM checks take two minutes and rule out half the cases.
Step 1: Get the exact time window
Find out when the VM actually went down, not when someone noticed. The guest uptime tells you the boot time.
# Windows, through Run Command (no RDP needed)
az vm run-command invoke -g rg-app -n vm-app01 --command-id RunPowerShellScript `
--scripts "(Get-CimInstance Win32_OperatingSystem).LastBootUpTime"
# Linux
az vm run-command invoke -g rg-app -n vm-app01 --command-id RunShellScript \
--scripts "uptime -s; last -x reboot shutdown | head -5"
Use a window of one hour either side of the boot time for the next steps.
Step 2: Check Resource Health for platform events
Resource Health records an annotation for every availability change, with a reason. This is the fastest way to prove or rule out a platform cause.
In the portal: VM > Help > Resource health. For a query you can paste into the ticket, use Azure Resource Graph:
HealthResources
| where type =~ 'microsoft.resourcehealth/resourceannotations'
| where properties.targetResourceId contains '/virtualMachines/vm-app01'
| extend occurred = todatetime(properties.occurredTime)
| where occurred > ago(7d)
| project occurred,
annotation = tostring(properties.annotationName),
reason = tostring(properties.reason),
category = tostring(properties.category),
context = tostring(properties.context),
summary = tostring(properties.summary)
| order by occurred desc
Run it from the CLI with the resource-graph extension:
az extension add --name resource-graph
az graph query -q "<query above>" --first 50 -o table
How to read the result:
| Annotation (examples) | Meaning | Next action |
|---|---|---|
VirtualMachineHostRebootedForRepair, VirtualMachineHostCrashed | Host hardware or software failure, unplanned | Platform cause. Attach the annotation to the incident; open a support case if you need an RCA |
VirtualMachinePlannedRedeploy, planned maintenance annotations | Azure maintenance you were notified about | Check Service Health planned maintenance and your maintenance configuration |
VirtualMachineRebootInitiatedByControlPlane with reason "Rebooted by user" | Someone or something called restart through ARM | Go to Step 3 to find the caller |
VirtualMachineStartInitiatedByControlPlane after a stop | VM was stopped, then started | Step 3 |
| No annotation in the window | Azure saw no outage, so the reboot happened inside the guest | Go to Step 4 |
Annotation names vary over time and Microsoft adds new ones; check the "Resource Health virtual machine health annotations" page for the current list.
Tip
The
contextfield often says "Platform Initiated" or "Customer Initiated". That one value usually answers the question your manager is asking.
Step 3: Find the caller in the Activity Log
If Resource Health says the restart came through the control plane, the Activity Log has the caller.
VM_ID=$(az vm show -g rg-app -n vm-app01 --query id -o tsv)
az monitor activity-log list --resource-id "$VM_ID" \
--start-time 2026-11-11T22:00:00Z --end-time 2026-11-12T02:00:00Z \
--query "[?contains(operationName.value, 'virtualMachines/')].{time:eventTimestamp, op:operationName.value, status:status.value, caller:caller}" \
-o table
Operations to look for:
Microsoft.Compute/virtualMachines/restart/actionMicrosoft.Compute/virtualMachines/deallocate/actionandstart/actionMicrosoft.Compute/virtualMachines/redeploy/actionMicrosoft.Compute/virtualMachines/write(a resize restarts the VM)Microsoft.Compute/virtualMachines/installPatches/action(Update Manager)
If the Activity Log is exported to Log Analytics, the same check across all VMs looks like this:
AzureActivity
| where TimeGenerated > ago(2d)
| where ResourceProviderValue =~ 'MICROSOFT.COMPUTE'
| where OperationNameValue has_any ('restart/action', 'deallocate/action', 'redeploy/action', 'installPatches/action')
| where ActivityStatusValue == 'Start' or ActivityStatusValue == 'Started'
| project TimeGenerated, _ResourceId, OperationNameValue, Caller, CallerIpAddress
| order by TimeGenerated desc
The Caller is a UPN for a person and an object ID (GUID) for a managed identity or service principal. Resolve a GUID with:
az ad sp show --id <guid> --query "{name:displayName, type:servicePrincipalType}"
Common non-human callers: an Automation account running a start/stop runbook, a DevOps service connection, Update Manager, or the auto-shutdown schedule (Microsoft.DevTestLab/schedules on the VM).
Step 4: Read the guest logs
No platform annotation and no ARM operation means the OS restarted itself.
Windows
az vm run-command invoke -g rg-app -n vm-app01 --command-id RunPowerShellScript --scripts @'
Get-WinEvent -FilterHashtable @{LogName='System'; Id=1074,1076,6005,6006,6008,41,1001; StartTime=(Get-Date).AddDays(-2)} |
Select-Object TimeCreated, Id, ProviderName, @{n='Msg';e={$_.Message.Substring(0,[Math]::Min(200,$_.Message.Length))}} |
Format-Table -AutoSize -Wrap
'@
| Event ID | Meaning |
|---|---|
| 1074 | Planned restart. The message names the process (for example TrustedInstaller.exe, svchost.exe for Windows Update) and the user |
| 6006 / 6005 | Clean shutdown / Event Log service started (boot) |
| 6008 | Previous shutdown was unexpected |
| 41 (Kernel-Power) | Rebooted without a clean shutdown: crash, hang or power loss from the host |
| 1001 (BugCheck) | Blue screen; the message has the stop code and the dump path |
An event 41 with no 1001 and a matching platform annotation is a host problem. An event 41 with a 1001 is a guest crash; collect C:\Windows\MEMORY.DMP or the minidump.
Linux
az vm run-command invoke -g rg-app -n vm-app01 --command-id RunShellScript --scripts '
journalctl --list-boots | tail -3
journalctl -b -1 -n 50 --no-pager
grep -iE "reboot|shutdown|panic|oom|watchdog" /var/log/messages /var/log/syslog 2>/dev/null | tail -20
'
journalctl -b -1 shows the end of the previous boot. A clean systemd-shutdown sequence means someone ran a reboot (check /var/log/auth.log or secure for sudo reboot, and unattended-upgrades or dnf-automatic logs). A log that stops mid-line means a crash or a host-side reset. Persistent journald storage must be enabled for -b -1 to work; on some images it isn't by default.
For a kernel panic, check the boot diagnostics serial log, which captures console output the journal never wrote:
az vm boot-diagnostics get-boot-log -g rg-app -n vm-app01 | tail -100
Step 5: Write it up
Put these into the incident ticket:
- Boot time from Step 1.
- The Resource Health annotation (name, context, time), or "none in window".
- The Activity Log caller, or "no ARM operation".
- The guest event or journal lines.
That is enough for the application owner and, if it was a platform event, enough for a support case.
Prevent it next time
- Alert on Resource Health. Create an activity log alert on the
ResourceHealthcategory for production VMs so you learn about platform reboots before the users do. - Control patch reboots. Use Update Manager maintenance configurations with a defined reboot setting instead of letting the guest reboot on its own schedule.
- Handle maintenance in the guest. Scheduled Events give a warning before most platform-initiated reboots; drain the node when you receive one.
- Remove single points of failure. If one VM rebooting is an incident, it belongs in an availability zone pair or a scale set behind a load balancer.
- Keep the logs. Export the Activity Log and collect the Windows System log or Linux syslog through Azure Monitor Agent, so the evidence survives even if the VM doesn't.
Warning
Don't "fix" a mystery reboot by redeploying the VM before you've collected the guest logs and the boot log. Redeploy moves the VM to a new host and the temporary disk is lost, along with any crash dump written there.