Azure Troubleshooting

When Azure Backup Jobs Fail: Diagnosing VM Agent, Snapshot, and Extension Errors

The job ran at 02:00 like every night. This morning the Recovery Services vault shows a red Failed against one VM, error code UserErrorGuestAgentStatusUnavailable, and the backup admin has already restarted the VM twice “just in case.” The other forty VMs in the same vault succeeded. Nothing changed — except, as always, something did. This is the most common operational incident in Azure Backup, the managed service that takes point-in-time copies of your Azure VMs into a vault you don’t run. It is maddening because the error you see is reported by the backup orchestrator in the vault, not by the thing that failed: the vault is saying “I asked the VM to take a snapshot and didn’t get a good answer.” Why it didn’t is the whole game, and at least a dozen root causes hide behind a handful of error strings.

This is the diagnostic playbook for failed VM backup jobs. We treat the failures not as one bug but as a small set of symptom classes — the agent is unreachable, the VMSnapshot extension failed, VSS couldn’t quiesce the disks, the snapshot succeeded but the data transfer to the vault failed, or a restore won’t complete — each with a fan-out of causes you confirm with specific commands. You will learn to read the backup pipeline end to end — vault orchestrator → Azure VM agent → VMSnapshot extension → in-guest VSS / pre-post scripts → instant-recovery snapshot → background copy into the vault — and to localise a failure to exactly one hop. Every diagnosis comes with the precise path to confirm it (the Backup jobs blade, the job error detail, the in-guest agent and extension logs, az backup, az vm) and the exact fix, with az CLI and Bicep where it applies. Because this is a reference you reach for mid-incident, the playbook, the error codes and the agent/extension knobs are all laid out as scannable tables.

By the end you will stop guessing and stop blindly restarting VMs. When a job fails you will know within minutes whether you face a stopped or out-of-date VM agent, a VMSnapshot extension in a failed state, a VSS writer that timed out under disk pressure, an NSG or firewall blocking egress to Azure Storage, a vault at its instant-restore snapshot limit, or simply a VM that was deallocated at backup time. Knowing which — and confirming it rather than assuming — turns a recurring nightly red into a one-time fix.

What problem this solves

Azure Backup hides a lot of moving parts so you can tick “backup enabled” and move on — a gift until a job fails, when it becomes an opaque wall. The job-failure pane gives you an error code and a deliberately generic one-line message, while the real evidence is split across the vault’s job detail, the VM’s extension status, and log files inside the guest OS the vault cannot show you. Not knowing which place maps to which failure costs you an afternoon of reading the wrong logs.

What breaks without this knowledge: an operator retries the job (sometimes succeeding by accident as a transient clears, teaching the wrong lesson), restarts the VM (occasionally fixing a wedged extension, usually doing nothing), or — worst — assumes the backup is fine because most nights are green, and only discovers the gap during a restore, when the recovery point they need was never created. A silent backup failure is a disaster waiting for the day you need the data.

Who hits this: essentially everyone running Azure VM backup. It bites hardest on Linux VMs where the agent or Python dependencies drift, application servers where VSS struggles to quiesce a busy database, locked-down networks with no clean egress to Azure Storage, VMs deallocated on a schedule (dev boxes, spot VMs), and subscriptions where someone tightened RBAC and the operator quietly lost permission. The fix is almost never “restart the VM” — it is “find the hop that failed and make it tell you why.”

Every symptom class this article covers, the question it forces, and the first place to look:

Symptom class What the orchestrator is really saying First question to ask First place to look Most common single cause
Agent unreachable “I couldn’t talk to the guest agent at all” Is the VM running and the agent Ready? VM → Properties → Agent status; az vm get-instance-view VM deallocated, or agent stopped / out of date
Snapshot / extension failure “The agent answered but the snapshot step failed” Did the VMSnapshot extension provision OK? Job error detail; VM → Extensions → VMSnapshot status Extension in failed state; needs reinstall
VSS / app-consistency failure “Snapshot ran but couldn’t quiesce the app” Did it fall back to crash-consistent or fail? Job detail; in-guest VSS / extension logs VSS writer timeout or error under load
Data-transfer failure “Snapshot is taken but the copy to the vault failed” Does the VM have egress to Storage? Job sub-task detail; NSG / UDR / firewall NSG/firewall blocking Storage; or transient
Restore won’t complete “The recovery point exists but restore is stuck/failed” Target capacity, region, or permissions? Restore job detail; target RG quota / RBAC Target staging account / disk SKU / RBAC issue

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You should understand the Azure Backup basics: a Recovery Services vault is the regional resource that stores recovery points and runs the backup policy (schedule + retention); a backup item is one protected resource (here, a VM); a backup job is a single run you watch succeed or fail. Know that VM backup is agent-based but agentless to install — it rides the Azure VM agent already on the VM and pushes a VMSnapshot extension the first time you protect it. Be comfortable running az in Cloud Shell, reading JSON, and connecting into a VM to read a log. New to backup? Start with Protect Your First Azure VM with Azure Backup: A Guided Walkthrough and come back when a job goes red.

This sits in the Observability & Troubleshooting track and assumes the protection fundamentals from Azure Backup and Site Recovery: Protecting Workloads from Loss and the resilience framing in BCDR Foundations on Azure: Making Sense of RTO, RPO, and the Resilience Spectrum. It pairs with Managed Identities Demystified: System vs User-Assigned and When to Use Each, since RBAC and identity sit behind several failure classes, and Azure Storage Redundancy Decoded: LRS vs ZRS vs GRS vs RA-GRS and How to Choose.

A quick map of who confirms what during a backup incident, so you read the right evidence first:

Layer What lives here Who usually owns it Failure classes it can cause
Vault / orchestrator Policy, schedule, retention, job history Backup admin Job scheduling, retention limits, vault throttling
VM agent (guest agent) Extension handler, status reporting VM / platform Agent unreachable; extension can’t be pushed
VMSnapshot extension The snapshot worker in-guest Backup + VM Extension provisioning failure, snapshot errors
In-guest VSS / scripts App quiescing (Windows VSS, Linux scripts) App / dev team App-consistency failure, writer timeouts
Managed disks Where the instant-recovery snapshot lives Platform Snapshot retention full; disk-state conflicts
Network (NSG/UDR/firewall) Egress to Azure Storage for data transfer Network team Data-transfer failure (copy to vault)
RBAC / identity Who may back up and restore Identity / platform Permission-denied on backup config or restore

Core concepts

Five mental models make every later diagnosis obvious.

The error code names the orchestrator’s complaint, not the in-guest root cause. The job lives in the vault; the work happens inside the VM. UserErrorGuestAgentStatusUnavailable or a VMSnapshot failure tells you which step the vault couldn’t complete — not why the guest failed it; the “why” is in the VM’s extension status and the in-guest logs. Reading the vault error and stopping is the biggest time-waster: the error names the hop to inspect, the inspection names the cause.

VM backup rides the Azure VM agent and a snapshot extension. The Azure VM agent (guest agent)WindowsAzureGuestAgent on Windows, walinuxagent on Linux — ships on Marketplace images and reports Ready/Not Ready. The first time you protect a VM, Azure Backup uses the agent to install the VMSnapshot extension (VMSnapshot / VMSnapshotLinux), and every later backup asks that extension to snapshot. So a backup needs two healthy things in the guest: an agent that is Ready, and a VMSnapshot extension whose provisioning state is Succeeded. If either is unhealthy, the job fails before it touches your disks.

Application-consistent is the goal; crash-consistent is the fallback. Backup aims for an application-consistent point — on Windows via VSS (Volume Shadow Copy Service), on Linux via pre-/post-snapshot scripts you provide. If those fail, it falls back to a crash-consistent snapshot (like pulling the power — disk intact, apps may need their own recovery). A job that succeeds with warnings usually means a crash-consistent point because app-consistency failed — a real signal, not noise.

The snapshot is fast; the transfer is where the network bites. Backup first takes an instant-recovery snapshot on the managed disks (default retention historically up to 5 days, configurable down to 1) — fast, and what powers near-instant restores — then a background copy moves the data into the vault. The phases fail differently: the snapshot phase on agent/extension/VSS problems; the transfer phase when the VM cannot reach Azure Storage (the data is read out via the guest), where NSGs, UDRs and firewalls cause grief unrelated to the snapshot.

Allocation and retention are finite. A vault item has an instant-restore snapshot retention window — keep too many on-demand snapshots and the next job fails until older ones age out. The VM must be running at backup time for an application-consistent result. And the operator needs the right RBAC. Run out of any of these — snapshot slots, allocation, permission — and you get a failure that looks like a bug but is a limit.

The vocabulary in one table

Before the deep sections, pin down every moving part. The glossary at the end repeats these for lookup; this table is the mental model side by side:

Concept One-line definition Where it lives Why it matters to job failures
Recovery Services vault Regional store + orchestrator for backups Subscription / resource group Runs the job; emits the error code
Backup item One protected resource (a VM) In the vault The thing whose job fails
Backup policy Schedule + retention rules In the vault Wrong window/retention → missed or capped jobs
Azure VM agent Guest agent that hosts extensions Inside the VM Not Ready → agent-unreachable failure
VMSnapshot extension The in-guest snapshot worker VM → Extensions Failed state → snapshot failure
VSS Windows app-quiescing service Inside Windows guest Writer timeout → app-consistency failure
Pre/post scripts Linux app-quiescing hooks Inside Linux guest Script error → app-consistency failure
Instant-recovery snapshot Fast snapshot on managed disks On the disks Retention cap → job fails until aged out
Data transfer Background copy snapshot → vault VM egress → Storage Blocked egress → transfer failure
Recovery point A restorable point-in-time copy In the vault What a restore consumes
Instant restore Restore from the on-disk snapshot From the snapshot Fast restore window; tied to retention

The backup error-code reference

Before the per-symptom anatomy, here is the lookup table you scan first: the error codes you realistically see on a failed Azure VM backup job, what each means, how to confirm it, and the first fix. The non-obvious ones are the UserError* agent/extension codes (which all point into the guest) and the gap between a job that fails and one that completes with warnings (crash-consistent fallback).

Error code / status Meaning Likely cause How to confirm First fix
UserErrorGuestAgentStatusUnavailable Orchestrator couldn’t get agent status VM deallocated, agent stopped / Not Ready / outdated VM → Properties → Agent status; az vm get-instance-view Start VM; start/update the agent; ensure it reports Ready
GuestAgentSnapshotTaskStatusError Agent reachable but snapshot task didn’t report status Extension wedged, in-guest blocker, COM/service down Job detail; VM → Extensions → VMSnapshot status Restart agent service; reinstall extension
ExtensionSnapshotFailedNoNetwork / UserErrorSnapshotFailedNoNetwork Snapshot/transfer failed due to no network path NSG/firewall/UDR blocking egress to Storage NSG effective rules; UDR; firewall logs Allow egress to Storage (service tag / endpoint)
ExtensionFailedVssWriterInBadState A VSS writer was not in a stable state App/VSS writer in failed/retryable state In-guest vssadmin list writers Restart the writer’s service; retry; fix the app
ExtensionConfigParsingFailure Extension config couldn’t be parsed/applied Corrupt/locked extension state on the VM VM → Extensions → VMSnapshot provisioning state Remove and reinstall the VMSnapshot extension
UserErrorVmNotInDesiredState VM not in a state backup can act on VM stopped/deallocated or mid-operation az vm get-instance-view power state Bring VM to Running; retry after other ops finish
UserErrorCrpReportedUserError The compute layer rejected the snapshot op Disk state conflict, concurrent op, lock Activity log on the VM; check running ops Resolve the conflicting op; remove blocking lock
UserErrorBackupOperationInProgress A backup/related op is already running Overlapping on-demand + scheduled run Backup jobs blade (in-progress job) Wait for the running job; serialise on-demand runs
UserErrorRequestDisallowedByPolicy Azure Policy blocked a needed resource Policy denies snapshot/staging resource creation Activity log → policy deny event Adjust policy scope/exemption for backup resources
DataTransferFailed / generic transfer error Snapshot OK, copy into vault failed Egress blocked, throttling, transient Job sub-task detail; NSG/firewall Fix egress; retry; check vault region health
Completed with warnings (crash-consistent) Job succeeded but not app-consistent VSS/scripts failed; fell back Job detail “consistency” field Fix VSS/scripts to regain app-consistency
UserErrorRpCollectionLimitReached / snapshot limit Too many instant-restore snapshots retained On-demand snapshots piling up vs retention Restore points / snapshot retention setting Let snapshots age out; reduce on-demand frequency

Three reading notes that save the most time:

Distinction The trap How to tell them apart
Job failed vs completed with warnings A green-with-warning job looks fine on the dashboard Open the job: a warning means a crash-consistent point was created (app-consistency failed) — still recoverable, but investigate
Agent-unreachable vs extension-failure Both can read as “snapshot didn’t run” If agent status is Not Ready / no status, it’s the agent. If agent is Ready but the VMSnapshot extension shows Failed, it’s the extension
Snapshot-phase vs transfer-phase failure Hours lost in the wrong logs If the recovery point was created but the job still failed, the transfer failed (network), not the snapshot

Anatomy of an agent-unreachable failure

Here the orchestrator never gets a usable answer from inside the VM: codes like UserErrorGuestAgentStatusUnavailable and GuestAgentSnapshotTaskStatusError. Four causes — scan the matrix, then read the matching detail:

# Cause Tell-tale signal Confirm with Real fix Band-aid that masks it
1 VM deallocated at backup time VM was Stopped (deallocated) at the scheduled hour az vm get-instance-view power state; activity log Align schedule with uptime; allow crash-consistent Retry later (only works once VM is up)
2 Agent stopped / Not Ready Agent status blank or “Not Ready” VM → Properties → Agent status Start/restart the agent service in-guest VM restart (sometimes restarts agent)
3 Agent out of date / broken Old agent version; extension push fails Agent version in instance view; in-guest logs Update/reinstall the VM agent None — old agent keeps failing
4 Wireserver / IMDS unreachable Agent can’t reach 168.63.129.16 In-guest agent log; NSG/UDR to platform Restore platform reachability (NSG/UDR) None

Cause 1 — The VM was deallocated (or stopped) at backup time

The most common cause of all. The backup fires at 02:00 but the VM is Stopped (deallocated) — a dev box on a shutdown schedule, an evicted spot VM, or left off. With no running guest agent, the orchestrator gets no status and the job fails. Confirm the power state:

# Current power state of the VM
az vm get-instance-view --name vm-app01 --resource-group rg-app-prod \
  --query "instanceView.statuses[?starts_with(code,'PowerState')].displayStatus" -o tsv
# Expect: "VM running"  (anything else at backup time explains the failure)

The activity log corroborates with the deallocate/start events. Fix. Align the schedule to when the VM is reliably up, or change the shutdown schedule. If the VM is meant to be off and you only need disk integrity, a crash-consistent point is acceptable — just know you aren’t getting app-consistency on a powered-off VM.

Cause 2 — The VM agent is stopped or reporting Not Ready

The agent is installed but its service isn’t running or is wedged, so it reports Not Ready (or nothing) and the orchestrator can’t get snapshot status. Confirm:

az vm get-instance-view --name vm-app01 --resource-group rg-app-prod \
  --query "instanceView.vmAgent.statuses[].displayStatus" -o tsv
# "Ready" is healthy; "Not Ready" / empty points at the agent

VM → Properties → Agent status shows Ready / Not Ready. Fix. Restart the agent in-guest — Windows: Restart-Service WindowsAzureGuestAgent; Linux: systemctl restart walinuxagent. The logs that hold the truth differ by OS: on Windows, C:\WindowsAzure\Logs\WaAppAgent.log (extensions under ...\Logs\Plugins\...); on Linux, /var/log/waagent.log (extensions to /var/log/azure/, the VMSnapshotLinux handler in its own subdirectory).

Cause 3 — The VM agent is out of date or broken

An old or corrupted agent can fail to push or run the extension even while appearing partly functional — common where walinuxagent/Python dependencies drift, or on long-lived custom images. Confirm the version and look for handler errors in waagent.log / WaAppAgent.log. Fix. Update or reinstall the agent, then validate with an on-demand backup.

Cause 4 — The platform endpoint (wireserver / IMDS) is unreachable

The agent reaches the platform on the host channel — 168.63.129.16 (wireserver) and IMDS at 169.254.169.254. A too-aggressive NSG, a UDR forcing all traffic through an appliance, or an in-guest firewall that blocks these leaves the agent unable to function, reporting Not Ready. Confirm with the in-guest agent log (it records wireserver failures) plus the NSG/UDR; fix by restoring reachability — these addresses must not be blackholed or denied. If the VM is also unreachable for management, Cannot RDP or SSH to an Azure VM? A First-Principles Troubleshooting Path walks the same plumbing.

Anatomy of a snapshot / extension failure

Here the agent is Ready but the VMSnapshot extension can’t do its job — the orchestrator reached the guest and asked for a snapshot, but the snapshot step failed. Four causes:

# Cause Tell-tale signal Confirm with Real fix
1 Extension in failed provisioning state VMSnapshot shows “Failed” / “Transitioning” stuck VM → Extensions → VMSnapshot status Remove and reinstall the extension
2 Missing dependency (Linux Python/handler) Linux extension errors on handler launch /var/log/azure/ extension log Fix Python/agent; update distro packages
3 Disk-state / concurrent-op conflict UserErrorCrpReportedUserError; op in progress Activity log; running disk operations Finish/cancel the conflicting op; retry
4 Exclusive lock / read-only resource Snapshot blocked by a resource lock Resource locks on VM/RG; activity log Remove or scope the lock for backup

Cause 1 — The VMSnapshot extension is in a failed state

The extension can land in a Failed provisioning state — corrupted state, an interrupted run, or an in-guest condition it can’t recover from — and once failed, every job fails until it’s healthy. Confirm:

# Extension provisioning state for VMSnapshot (name differs Win vs Linux)
az vm extension list --vm-name vm-app01 --resource-group rg-app-prod \
  --query "[?contains(name,'VMSnapshot')].{name:name, state:provisioningState}" -o table

Fix. Remove the extension and let the next backup reinstall it — Azure Backup re-pushes it automatically, so deleting the broken instance is safe. Then run an on-demand backup to re-provision and validate:

# Remove the failed VMSnapshot extension; the next backup re-installs it cleanly
az vm extension delete --vm-name vm-app01 --resource-group rg-app-prod \
  --name VMSnapshot   # use VMSnapshotLinux on Linux VMs

Cause 2 — A missing in-guest dependency (especially Linux)

VMSnapshotLinux relies on the agent and its Python runtime; if the distro’s Python is upgraded out from under the agent, a package is missing, or the handler can’t launch, the snapshot fails even though the agent reports Ready. Confirm in /var/log/azure/ (the VMSnapshotLinux handler directory). Fix. Repair the dependencies — update walinuxagent, ensure a supported Python, reinstall the extension. On custom or hardened images this is the usual culprit; validate the agent before mass-deploying.

Cause 3 — A disk-state conflict, and Cause 4 — a resource lock

If another operation is touching the disks — a resize, another snapshot, a disk attach/detach, or a previous backup that hasn’t released — the compute layer rejects the snapshot with UserErrorCrpReportedUserError or UserErrorVmNotInDesiredState. Confirm via the VM’s activity log (in-flight ops) and the Backup jobs blade (an overlapping run); fix by letting the other op finish, then retrying. Serialise on-demand runs so they don’t collide with the schedule — UserErrorBackupOperationInProgress is two jobs racing. Separately, a ReadOnly resource lock can block the staging/snapshot resources Backup creates (a CanNotDelete lock generally does not) — list locks with az lock list, then scope or remove the ReadOnly lock for the window. The extension-repair options compared:

Repair action What it does When to use Risk / note
Retry the job Re-runs the same job Transient one-off failure No-op if cause is persistent
Restart the agent service Restarts in-guest agent Agent wedged but installed Brief in-guest disruption only
Remove + auto-reinstall extension Deletes VMSnapshot; next backup re-adds Extension in failed state Safe; Backup re-pushes automatically
Update / reinstall the agent Fresh agent + dependencies Out-of-date or broken agent Validate with on-demand run after
Remove a ReadOnly lock Frees resource creation Lock blocking staging resources Re-apply lock after if required

Anatomy of an application-consistency (VSS) failure

This one hides in plain sight: the job often completes with warnings rather than failing outright, because Backup created a crash-consistent point after VSS (Windows) or the pre/post scripts (Linux) failed. The disk is intact, but a database may need its own crash recovery on restore — treat a warning as a real defect, not a green light. The causes:

# Cause Tell-tale signal Confirm with Real fix
1 VSS writer timed out / in bad state “VSS writer … bad state”; warning consistency vssadmin list writers (look for non-Stable) Restart the writer’s service; reduce disk pressure
2 Heavy I/O / disk pressure during snapshot App-consistency fails only under load Disk IOPS/queue metrics at backup time Move backup window off peak; faster disk SKU
3 Free space too low for shadow copy VSS can’t allocate shadow storage Free space on protected volumes Free space; resize the volume
4 Linux pre/post script error / missing Linux VM only ever crash-consistent /etc/azure/ script config; script exit code Provide/fix the pre/post scripts

Cause 1 — A VSS writer is in a bad state

Each application registers a VSS writer (SQL Server, AD, etc.). A writer in a non-Stable state blocks the application-consistent snapshot, and Backup falls back to crash-consistent. Confirm inside the Windows guest:

:: Elevated command prompt — every writer should read "State: [1] Stable", "Last error: No error"
vssadmin list writers

Fix. Restart the service behind the bad writer (for SQL, the SQL Server service), then re-run an on-demand backup. A persistently bad writer usually means the app is under stress at snapshot time.

Cause 2 — Disk pressure makes VSS time out

VSS briefly quiesces I/O for the shadow copy; on a VM hammering its disks at the backup hour the quiesce times out and app-consistency fails. Confirm by correlating the job time with disk IOPS / queue-depth metrics — failing only under load is the tell. Fix. Move the window to a quieter time and/or a higher-throughput disk SKU; Azure VM Disk Types Demystified: Standard HDD, Standard/Premium SSD, Premium v2 and Ultra Disks lays out the IOPS/throughput ceilings that govern how fast it flushes.

Cause 3 — Free space, and Cause 4 — Linux scripts

VSS needs room for the shadow copy’s differences; on a nearly-full volume it can’t allocate that space and the snapshot degrades — confirm free space on each protected volume and fix by freeing or growing it (a chronically full data disk is the usual offender). On Linux there is no VSS: application-consistency requires pre-/post-snapshot scripts (referenced from the agent config) that quiesce and unquiesce your app. Absent, wrong, or non-zero-exit scripts mean only crash-consistent points — provide correct, fast, idempotent scripts that exit 0, which is why “my Linux VM is never application-consistent.” The two models compared:

Aspect Windows (VSS) Linux (pre/post scripts)
Quiescing mechanism VSS writers (built in) Your scripts (you author)
Default consistency Application-consistent Application-consistent only if scripts present and succeed
Common failure Writer in bad state / timeout Missing or failing script
Where to look vssadmin list writers; event logs /var/log/azure/; script config + exit code
Fallback Crash-consistent (job warns) Crash-consistent (job warns)
Fix lever Restart writer service; free space; off-peak window Author/fix scripts; ensure exit 0

Anatomy of a data-transfer failure

Here the snapshot succeeded — a recovery point may even appear — but the background copy into the vault failed. Because the data is read out via the guest, this phase fails almost entirely on egress to Azure Storage. The tell: a job that snapshotted fine yet went red, or *NoNetwork*/DataTransferFailed codes. The causes:

# Cause Tell-tale signal Confirm with Real fix
1 NSG / firewall blocks egress to Storage *SnapshotFailedNoNetwork*; snapshot OK, copy fails NSG effective rules; firewall logs Allow outbound to Storage (service tag)
2 UDR blackholes platform/Storage traffic Forced-tunnel route with no return path Effective routes on the NIC Fix UDR; route Storage correctly
3 Private endpoint / DNS misconfig Private vault/storage path doesn’t resolve DNS resolution from the VM Correct private DNS zone / endpoint
4 Vault throttling / transient Intermittent transfer failures, then success on retry Job history pattern; retry Retry; stagger schedules to spread load

Cause 1 — An NSG or firewall blocks egress to Azure Storage

The most common transfer failure. The snapshot data must reach Azure Storage, and a locked-down NSG or an in-path Azure Firewall/NVA without the right allow-rule blocks it: the snapshot succeeds (local), the transfer fails (UserErrorSnapshotFailedNoNetwork). Confirm the effective NSG rules on the VM’s NIC:

# Effective outbound rules on the VM's NIC — is Storage egress allowed?
az network nic list-effective-nsg \
  --name vm-app01VMNic --resource-group rg-app-prod -o table

Fix. Allow outbound to the Storage service tag, or open the firewall/NVA for it — the service tag is the clean way, with no hard-coded IPs:

resource allowStorageEgress 'Microsoft.Network/networkSecurityGroups/securityRules@2023-11-01' = {
  parent: nsg
  name: 'Allow-Backup-Storage-Egress'
  properties: {
    priority: 200
    direction: 'Outbound'
    access: 'Allow'
    protocol: 'Tcp'
    sourceAddressPrefix: 'VirtualNetwork'
    sourcePortRange: '*'
    destinationAddressPrefix: 'Storage'   // service tag; region-scoped form: Storage.<region>
    destinationPortRange: '443'
  }
}

Cause 2 — A UDR blackholes the traffic

A forced-tunnel UDR (0.0.0.0/0 → an on-prem appliance) sends Storage-bound traffic somewhere with no return path, and the copy hangs/fails. Confirm the effective routes:

az network nic show-effective-route-table \
  --name vm-app01VMNic --resource-group rg-app-prod -o table

Fix. Route Storage-bound traffic correctly — exempt the Storage service tag from the tunnel, or send it via an endpoint that reaches Storage; the route table is the source of truth. Cause 3 — private endpoint / DNS. With the vault or storage behind private endpoints, the VM must resolve those private names via the correct private DNS zone; a missing zone link means it resolves a public name it can’t reach and the transfer fails. Confirm by resolving the name from the VM (expect the private IP); fix the DNS zone link. Cause 4 — throttling / transient. Occasionally the transfer fails transiently and a plain retry succeeds — don’t over-engineer a one-off, but if it recurs across many VMs at the same minute, stagger schedules. What’s allowed to reach where, by topology:

Topology How the VM reaches Storage for transfer What you must allow Common break
Default (public egress) Out to Azure Storage public endpoints NSG outbound to Storage (443) NSG denies all outbound
With Azure Firewall / NVA Through the firewall to Storage Firewall rule for Storage egress No allow-rule on the NVA
Forced tunnel (UDR) Per the route table Storage exempt from 0.0.0.0/0 tunnel Blackholed via on-prem
Private endpoint on vault/storage To the private IP via private DNS Private DNS zone link to the VNet DNS resolves public, not private

Architecture at a glance

Hold the whole pipeline as a single left-to-right path and every error code tells you where to stand. On the far left is the Recovery Services vault — the regional brain. It owns the policy (when to run, how long to keep) and the job you see go green or red, but does no in-guest work; it orchestrates. When the schedule fires, the vault reaches into the VM through the Azure VM agent, which must be Ready before anything else happens. If the vault can’t get a status from that agent (VM deallocated, agent stopped, platform endpoint unreachable), you never leave this first hop — the agent-unreachable class.

One hop in, the agent hands off to the VMSnapshot extension inside the guest — the worker that freezes and captures the disks. It must be in a Succeeded provisioning state; if it’s wedged or missing a dependency, the request dies here (the extension-failure class). The extension then triggers application quiescing: on Windows it calls VSS so writers flush; on Linux it runs your pre/post scripts. Succeed and you get an application-consistent point; fail and Backup falls back to crash-consistent and the job warns — the consistency class, easy to miss because the job still looks “done.”

With the disks quiesced, the platform takes the instant-recovery snapshot on the managed disks — fast, local, the thing that powers near-instant restores — held for a finite retention window (pile up on-demand snapshots and you hit the cap). Finally, a background copy reads the snapshot out of the guest and ships it to the vault over the network to Azure Storage — the only phase that depends on the VM’s egress, and where NSGs, UDRs and firewalls bite. The mental shortcut: agent → extension → VSS/scripts → snapshot → transfer — read the error code, place it on that line, inspect that one hop, ignore the other four. Restores run the line in reverse (vault → recovery point → new disks/VM in a target resource group), which is why restore failures cluster around the target — capacity, SKU, region, RBAC — not the source guest.

Real-world scenario

Meghdoot Logistics runs 60 Azure VMs across two regions — Windows application servers, SQL-on-VM database hosts, and a dozen Linux API workers — backed up by two Recovery Services vaults on a nightly policy (app-consistent at 02:00, 30-day retention, 5-day instant-restore). For a year it was boring and green. Then a platform refresh changed two things at once: the network team rolled out a forced-tunnel UDR pushing all egress through a new Azure Firewall, and the database team migrated three SQL hosts onto larger data disks running much busier overnight ETL. Next morning the dashboard lit up with two different failure patterns, and the on-call instinct — “restart the VMs” — fixed nothing.

The first pattern hit all the Linux API workers and several app servers: UserErrorSnapshotFailedNoNetwork. The engineer almost opened a support ticket, then remembered the pipeline — a NoNetwork code means the snapshot succeeded but the transfer failed, so it’s egress, not the guest. az network nic show-effective-route-table on one worker showed a 0.0.0.0/0 route to the firewall with no rule permitting the Storage service tag: the new forced tunnel was blackholing the backup copy. The network team added a Storage egress allow-rule on the firewall (plus a Storage NSG rule for belt-and-braces), and the next on-demand run transferred cleanly — fleet-wide green within the hour.

The second pattern was subtler and only on the three migrated SQL hosts: the jobs succeeded — but with warnings, “completed with crash-consistency.” Because the dashboard looked green-ish, nobody had flagged it — the kind of thing that bites only at restore. Inside one host, vssadmin list writers showed the SQL Server VSS writer in a non-Stable state: the heavy ETL was pinning the disks at exactly 02:00 and VSS was timing out on the quiesce. The two-part fix moved that vault’s schedule to 23:30 (before the ETL) for the database hosts and bumped their data disks to a higher-throughput SSD tier so the quiesce flushes faster. After that, the writers read Stable at backup time and the jobs returned to application-consistent, no warning.

The lesson, written into their runbook: read the error class before you touch the VM. A NoNetwork code is a network ticket, not a VM restart; a warning is a real defect — a crash-consistent SQL backup is a landmine you only find at restore time. Two simultaneous changes produced two unrelated failure classes that “restart everything” could never have fixed. Total cost of the actual fixes: one firewall rule, one schedule change, one disk-tier bump — no support ticket, no new vault, a far more trustworthy nightly run.

Advantages and disadvantages

Knowing how Azure VM backup fails is inseparable from knowing what the agent-and-snapshot design buys you and what it costs. The trade-offs:

Advantages Disadvantages
Agentless to install — rides the existing VM agent; no separate backup agent to deploy Wholly dependent on the VM agent being healthy and Ready
Application-consistent points via VSS / scripts — restorable without manual recovery App-consistency silently degrades to crash-consistent on VSS/script failure
Instant-recovery snapshots enable near-instant restores Snapshot retention is finite; on-demand pile-up causes job failures
Managed vault — no infrastructure to run, regional durability options Errors surface as vault codes; the real cause is in-guest, splitting your evidence
Centralised policy, RBAC, and reporting across many VMs A network change (NSG/UDR/firewall) can break the transfer for the whole fleet at once
Works across Windows and Linux with the same workflow Linux app-consistency needs you to author and maintain pre/post scripts

The agentless, policy-driven model scales beautifully across hundreds of VMs — enable a policy and walk away. The downside bites the moment the guest or network changes: the failure is reported in one place (the vault) and caused in another (the guest or network), making diagnosis harder than with a self-contained product — exactly why this playbook exists. Crash-consistent fallback is itself a feature and a trap: protective when VSS fails, but it lets a silently-degraded backup look healthy unless you watch for warnings.

Hands-on lab

This lab provisions a VM, protects it, deliberately breaks two failure classes, observes the errors, fixes them, and validates with an on-demand backup. It uses a B2s VM (~₹2–3/hour when running; deallocate or delete after) and Cloud Shell.

1. Create a resource group, vault, and VM.

az group create --name rg-bk-lab --location centralindia

az backup vault create --name rsv-bk-lab --resource-group rg-bk-lab \
  --location centralindia

az vm create --name vm-bk-lab --resource-group rg-bk-lab \
  --image Ubuntu2204 --size Standard_B2s \
  --admin-username azureuser --generate-ssh-keys

2. Enable backup with the default policy and run one on-demand backup.

az backup protection enable-for-vm \
  --vault-name rsv-bk-lab --resource-group rg-bk-lab \
  --vm vm-bk-lab --policy-name DefaultPolicy

# First on-demand run — this also pushes/validates the VMSnapshot extension
az backup protection backup-now \
  --vault-name rsv-bk-lab --resource-group rg-bk-lab \
  --container-name vm-bk-lab --item-name vm-bk-lab \
  --backup-management-type AzureIaasVM \
  --retain-until 05-07-2026

3. Watch the job and read its detail.

# List recent jobs and their status
az backup job list --vault-name rsv-bk-lab --resource-group rg-bk-lab \
  --query "[].{name:name, op:properties.operation, status:properties.status}" -o table

# Drill into the most recent job (substitute its name)
az backup job show --vault-name rsv-bk-lab --resource-group rg-bk-lab \
  --name <job-name> --query "properties.{status:status, error:extendedInfo.propertyBag}" -o json

Expected: Completed. Note the VMSnapshot extension now exists on the VM (az vm extension list --vm-name vm-bk-lab --resource-group rg-bk-lab -o table).

4. Break failure class A — agent unreachable (deallocate the VM). Stop and deallocate the VM, then trigger a backup:

az vm deallocate --name vm-bk-lab --resource-group rg-bk-lab
az backup protection backup-now \
  --vault-name rsv-bk-lab --resource-group rg-bk-lab \
  --container-name vm-bk-lab --item-name vm-bk-lab \
  --backup-management-type AzureIaasVM --retain-until 05-07-2026

Watch the job: a deallocated VM yields UserErrorGuestAgentStatusUnavailable / UserErrorVmNotInDesiredState — no running agent to talk to. Confirm:

az vm get-instance-view --name vm-bk-lab --resource-group rg-bk-lab \
  --query "instanceView.statuses[?starts_with(code,'PowerState')].displayStatus" -o tsv
# "VM deallocated" — there's your cause

5. Fix class A and revalidate. Start the VM, wait for the agent to report Ready, re-run:

az vm start --name vm-bk-lab --resource-group rg-bk-lab
az vm get-instance-view --name vm-bk-lab --resource-group rg-bk-lab \
  --query "instanceView.vmAgent.statuses[].displayStatus" -o tsv   # expect "Ready"
az backup protection backup-now --vault-name rsv-bk-lab --resource-group rg-bk-lab \
  --container-name vm-bk-lab --item-name vm-bk-lab \
  --backup-management-type AzureIaasVM --retain-until 05-07-2026

6. Break failure class B — data-transfer egress. Add an NSG rule that denies all outbound (simulating a locked-down network that blocks Storage egress), then back up:

NSG=$(az network nsg list -g rg-bk-lab --query "[0].name" -o tsv)
az network nsg rule create --resource-group rg-bk-lab --nsg-name "$NSG" \
  --name Deny-All-Out --priority 4000 --direction Outbound --access Deny \
  --protocol '*' --source-address-prefixes '*' --destination-address-prefixes '*' \
  --destination-port-ranges '*'
az backup protection backup-now --vault-name rsv-bk-lab --resource-group rg-bk-lab \
  --container-name vm-bk-lab --item-name vm-bk-lab \
  --backup-management-type AzureIaasVM --retain-until 05-07-2026

The job should fail in the transfer phase (a *NoNetwork*-class error). Confirm the block with effective rules: az network nic list-effective-nsg --name vm-bk-labVMNic --resource-group rg-bk-lab -o table.

7. Fix class B (allow Storage egress) and validate.

az network nsg rule create --resource-group rg-bk-lab --nsg-name "$NSG" \
  --name Allow-Storage-Out --priority 300 --direction Outbound --access Allow \
  --protocol Tcp --source-address-prefixes VirtualNetwork \
  --destination-address-prefixes Storage --destination-port-ranges 443
az backup protection backup-now --vault-name rsv-bk-lab --resource-group rg-bk-lab \
  --container-name vm-bk-lab --item-name vm-bk-lab \
  --backup-management-type AzureIaasVM --retain-until 05-07-2026   # expect Completed

8. Teardown. Disable protection and delete the resource group:

az backup protection disable --vault-name rsv-bk-lab --resource-group rg-bk-lab \
  --container-name vm-bk-lab --item-name vm-bk-lab \
  --backup-management-type AzureIaasVM --delete-backup-data true --yes
az group delete --name rg-bk-lab --yes --no-wait

You have now seen two distinct failure classes produce two distinct error families, confirmed each at the correct hop, and validated each fix — exactly the loop you run in production.

Common mistakes & troubleshooting

This is the centerpiece. Read the prose once; keep the table open at 02:00. It spans the everyday failures (deallocated VM, blocked egress) and the nastier ones (failed extension, VSS in a bad state, snapshot-retention cap), with the exact command or path to confirm and the real fix.

# Symptom Root cause Confirm (exact cmd / portal path) Fix
1 Job fails UserErrorGuestAgentStatusUnavailable VM deallocated, or agent stopped / Not Ready az vm get-instance-view ... PowerState; VM → Properties → Agent status Start the VM; restart the agent service; ensure it reports Ready
2 Job fails on a VM that’s clearly running Agent service wedged or out of date az vm get-instance-view ... vmAgent.statuses; in-guest WaAppAgent.log/waagent.log Restart/update the agent; re-run on-demand to validate
3 GuestAgentSnapshotTaskStatusError Extension reached but snapshot task never reported Job detail; VM → Extensions → VMSnapshot provisioning state Restart agent; if extension Failed, remove it (auto-reinstalls)
4 ExtensionConfigParsingFailure / extension stuck Transitioning Corrupt/locked VMSnapshot extension state az vm extension list --query "[?contains(name,'VMSnapshot')]" az vm extension delete --name VMSnapshot[Linux]; next backup reinstalls
5 Linux VM: extension fails on handler launch Broken walinuxagent / missing Python dependency /var/log/azure/ + /var/log/waagent.log Update walinuxagent/Python; reinstall extension; fix the base image
6 Job completes with warnings (crash-consistent) VSS writer in bad state, or Linux scripts failed/missing Job detail “consistency”; in-guest vssadmin list writers Restart the writer’s service; for Linux, author/fix pre/post scripts
7 App-consistency fails only on busy nights Disk pressure makes VSS quiesce time out Disk IOPS/queue metrics at backup time Move backup window off-peak; higher-throughput disk SKU
8 VSS snapshot fails on one volume Insufficient free space for the shadow copy Free space on the protected volume Free space / grow the volume
9 UserErrorSnapshotFailedNoNetwork (snapshot OK, copy fails) NSG/firewall blocks egress to Azure Storage az network nic list-effective-nsg ...; firewall logs Allow outbound to Storage service tag (443); open the NVA
10 Transfer hangs/fails behind a forced tunnel UDR 0.0.0.0/0 blackholes Storage traffic az network nic show-effective-route-table ... Exempt Storage from the tunnel; fix the route
11 Transfer fails with private endpoints in play VM resolves public name, can’t reach private vault/storage Resolve the name from the VM; check private DNS zone link Link the correct private DNS zone; fix the endpoint
12 UserErrorVmNotInDesiredState / UserErrorCrpReportedUserError Disk-state conflict or concurrent operation VM activity log for in-flight ops; Backup jobs for overlap Let the other op finish/cancel it; then retry
13 UserErrorBackupOperationInProgress On-demand backup racing the scheduled run Backup jobs blade shows an in-progress job Wait for the running job; don’t fire overlapping on-demand runs
14 New job fails referencing snapshot/restore-point limit Too many instant-restore snapshots retained Restore points list; instant-restore retention setting Let older snapshots age out; cut on-demand frequency; check retention
15 UserErrorRequestDisallowedByPolicy Azure Policy denies a resource Backup must create Activity log → policy deny event Adjust policy scope or add an exemption for backup resources
16 First-ever backup of a VM fails immediately Unsupported config, or agent never installed/Ready VM → Extensions (no VMSnapshot); agent status Install/repair agent; verify the VM/OS is a supported config

Per-symptom detail for the ones that trip people most:

Agent-unreachable (rows 1–2). Separate “is the VM even up?” from “is the agent healthy?” A deallocated VM is row 1; a running VM with a Not Ready agent is row 2 — az vm get-instance-view answers both (PowerState and vmAgent.statuses). Restarting the VM occasionally fixes row 2 by restarting the agent but tells you nothing; restart the agent service instead and you fix it and confirm the cause.

Extension failure (rows 3–5). The reliable repair for a wedged VMSnapshot extension is to delete it — Azure Backup re-pushes it on the next run, so this is safe, not destructive. On Linux, suspect the agent’s Python/dependencies first; a distro upgrade that moved Python is the classic cause and bites whole fleets built from one image.

Consistency warning (rows 6–8). Treat completed with warnings as a defect. A crash-consistent database backup will likely need crash recovery on restore — fine for a stateless web server, a problem for a transactional database. vssadmin list writers is your truth on Windows (every writer should read Stable / No error); on Linux, “always crash-consistent” almost always means missing or failing pre/post scripts.

Transfer failure (rows 9–11). A NoNetwork code is a network problem, not a VM one — the snapshot already succeeded. Go straight to effective NSG rules and the route table; don’t read in-guest application logs. The Storage service tag is the clean allow-target so you never hard-code IP ranges.

Best practices

Security notes

Cost & sizing

The bill drivers and how they interact with the failure classes:

A rough monthly picture for one ~200 GB Windows VM, daily backup, 30-day retention on LRS: a per-instance fee plus the incremental storage of ~30 restore points typically lands in the low thousands of INR per VM per month — less with shorter retention, more with GRS. The drivers:

Cost driver What you pay for Lever to control it Watch-out
Protected-instance fee Per VM, by used-size bucket Right-size the VM; remove dead protected items Stale items still bill — clean them up
Recovery-point storage Space all retained points consume Retention length; backup frequency Long retention multiplies storage
Storage replication (LRS/ZRS/GRS) Durability tier of vault storage Choose per data criticality GRS noticeably pricier than LRS
Instant-restore snapshots Snapshot storage for the window Instant-restore retention days Too many on-demand snapshots → cap + cost
Restore staging Temp resources during restore Clean up scratch RGs after test restores Forgotten restore targets keep billing
Network fix (NAT/firewall) Hourly + per-GB on the path Scope egress narrowly to Storage Small, but real if you add a NAT GW

Interview & exam questions

1. A nightly VM backup fails with UserErrorGuestAgentStatusUnavailable. What does that mean and what do you check first? The orchestrator couldn’t get a usable status from the Azure VM agent inside the guest. First check whether the VM is even running (az vm get-instance-viewPowerState) — a deallocated VM is the most common cause — then the agent status (Ready vs Not Ready). Fix by starting the VM and/or restarting/updating the agent so it reports Ready.

2. A job shows green “completed with warnings.” Is the backup fine? Not necessarily — a warning typically means Backup created a crash-consistent recovery point because application-consistency failed (VSS in a bad state on Windows, or missing/failing pre/post scripts on Linux). The disk is recoverable, but a database may need crash recovery on restore. Open the job to read the consistency, fix the underlying VSS writer or scripts, and re-validate.

3. The snapshot phase succeeds but the job still fails with a NoNetwork error. Where’s the problem? The data-transfer phase — the background copy into the vault — failed because the VM has no egress to Azure Storage. Confirm with the NIC’s effective NSG rules and route table; the cause is almost always an NSG/firewall blocking outbound to Storage or a forced-tunnel UDR. Fix by allowing the Storage service tag (443) and/or exempting it from the tunnel.

4. How do you repair a VMSnapshot extension stuck in a failed provisioning state? Remove the extension (az vm extension delete --name VMSnapshot / VMSnapshotLinux); Azure Backup re-installs it on the next run, so deleting the broken instance is the safe, reliable repair. Then trigger an on-demand backup to re-provision and confirm.

5. Why might a Linux VM consistently get only crash-consistent backups while a Windows VM gets application-consistent ones? Windows uses VSS (built in); Linux has no VSS, so application-consistency requires pre-/post-snapshot scripts that you author and the agent runs. Absent, misconfigured, or non-zero-exit scripts mean Backup falls back to crash-consistent. Provide correct, fast scripts that exit 0.

6. What is the instant-recovery snapshot, and how can it cause job failures? Azure Backup first takes a fast instant-recovery snapshot on the managed disks (default retention historically up to 5 days, configurable) to enable near-instant restores, then copies data to the vault. Accumulate too many snapshots (frequent on-demand runs) and you hit the retention cap, and the next job fails until older snapshots age out. Right-size the retention window and on-demand frequency.

7. A VM is running and the agent is Ready, but the job fails UserErrorVmNotInDesiredState. What’s going on? The compute layer can’t take the snapshot because the VM or its disks are in a conflicting state — a concurrent resize, another snapshot, a disk attach/detach, or an overlapping backup. Check the VM’s activity log for in-flight operations and the Backup jobs blade for an overlapping run; let it finish, then retry.

8. How do you protect backups from accidental or malicious deletion? Enable soft delete so deleted backup data is retained for a recovery window, use an immutable vault / multi-user authorisation to prevent retention reduction or deletion, and restrict who can disable protection with least-privilege RBAC (Backup Operator vs Backup Contributor). These defend against the ransomware pattern of disabling backups before encrypting.

9. Two VMs back up to the same vault; one fails UserErrorRequestDisallowedByPolicy. Why one and not both? An Azure Policy denies a resource Backup must create for that VM’s scope (blocking a snapshot or staging resource by location, SKU, or naming). The activity log shows the deny event. Fix by scoping the policy to exclude backup-created resources or adding an exemption — the other VM simply isn’t in the denying scope.

10. App-consistency fails only on busy database nights. Cause and fix? Heavy disk I/O at the backup hour makes the VSS quiesce time out, so Backup falls back to crash-consistent — confirm by correlating the job time with disk IOPS/queue-depth metrics. Fix by moving the window off the peak I/O period and/or to a higher-throughput disk SKU so the quiesce flushes within the window.

11. Which RBAC roles govern who can run and configure backups, and why does it matter for failures? Backup Operator can run backups and restores; Backup Contributor can also manage policy/protection; broad roles like Owner/Contributor cover everything. It matters because a missing or revoked role is itself a failure cause — config or restore operations get permission-denied — so least-privilege must be deliberate, not accidental.

12. How do you validate a fix without waiting for the nightly schedule? Trigger an on-demand backup (az backup protection backup-now) and watch the job to Completed (and check it’s application-consistent, not just completed-with-warnings). On-demand runs also re-push the VMSnapshot extension, so they double as the validation step after an agent update or extension repair.

These map to AZ-104 (Administrator)back up and restore Azure VMs — and AZ-305 (Solutions Architect)design business continuity; the redundancy/identity angles touch storage replication and RBAC. A compact cert-mapping for revision:

Question theme Primary cert Exam objective area
VM agent, extension, snapshot pipeline AZ-104 Back up and restore Azure VMs
Application vs crash consistency (VSS) AZ-104 Configure and manage backups
Vault, policy, retention, instant restore AZ-104 Manage Recovery Services vaults
Soft delete, immutability, RBAC AZ-104 / AZ-500 Protect backup data; secure resources
BCDR design, RTO/RPO, redundancy AZ-305 Design for business continuity
Restore targets, region, capacity AZ-104 / AZ-305 Restore and recover workloads

Quick check

  1. A backup fails with UserErrorGuestAgentStatusUnavailable. What is the first thing to check, and the single command that answers it?
  2. A job reports “completed with warnings — crash-consistent.” Why is that not necessarily fine, and where do you look on Windows to find the cause?
  3. The snapshot succeeds but the job fails with a NoNetwork error. Which phase failed, and what do you allow to fix it?
  4. The VMSnapshot extension is stuck in a Failed state. What is the safe, reliable repair?
  5. Your Linux VM only ever produces crash-consistent recovery points. Why, and what’s the fix?

Answers

  1. Whether the VM is actually running — a deallocated VM has no agent to talk to. az vm get-instance-view shows both the PowerState and the agent’s Ready/Not Ready status in one call.
  2. Because a warning means Backup created a crash-consistent point after application-consistency failed — a database may need crash recovery on restore. On Windows, run vssadmin list writers (elevated); every writer should read Stable / No error, and a non-Stable one is the cause.
  3. The data-transfer phase (the background copy of the snapshot into the vault), which depends on the VM’s egress to Azure Storage. Allow outbound to the Storage service tag (port 443) in the NSG and exempt it from any forced-tunnel UDR.
  4. Remove the extension (az vm extension delete --name VMSnapshot / VMSnapshotLinux); Azure Backup re-installs it automatically on the next backup run. Then trigger an on-demand backup to re-provision and validate.
  5. Linux has no VSS; application-consistency requires pre-/post-snapshot scripts that you author and the agent runs. If they’re missing or failing, Backup falls back to crash-consistent. Provide correct, fast scripts that exit 0.

Glossary

Next steps

You can now localise any failed Azure VM backup job to a hop — agent, extension, VSS, snapshot, or transfer — and fix it. Build outward:

AzureAzure BackupTroubleshootingVM AgentVSSRecovery Services VaultSnapshotBackup Extension
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading