The Scenario
We were managing a hybrid Microsoft 365 environment — roughly 4,200 Entra ID-joined devices, E5 licensing across the board, Conditional Access policies numbering in the mid-forties, and a handful of junior admins with Global Administrator rights that we'd been meaning to scope down for months. You already know where this is going.
A change request came through to modify a Conditional Access policy blocking legacy authentication. The admin making the change misidentified the policy, modified the wrong one — specifically, the policy enforcing MFA for all users — and saved it in a disabled state. It sat that way for six hours before a security alert from Defender for Cloud Apps flagged unusual sign-in patterns. By that point, a credential stuffing campaign had already successfully authenticated roughly 30 accounts. No MFA challenge. No block. Just open doors.
The recovery process was painful. There was no automated configuration backup. The previous policy state existed only in the audit log, which required manual reconstruction. It took three engineers the better part of a day to restore every Conditional Access policy, Named Location, and Authentication Strength definition to a known-good state — and even then, we weren't fully confident the reconstruction was accurate.
That incident was the forcing function that pushed us to take Microsoft Entra Backup and Recovery seriously. The feature, now generally available and deeply integrated into the Entra admin experience, is not just a checkbox compliance item. It's operational insurance for the identity plane — and after running it in production for several months, there are things about it that the official documentation glosses over entirely.
Why This Matters
Identity is not just another workload in your Microsoft 365 estate. It's the control plane. When Conditional Access breaks, every downstream security control that depends on it — device compliance enforcement, app protection policy evaluation, Privileged Identity Management gates — becomes unreliable or completely bypassed. Intune device compliance signals flow into Conditional Access. If the policy consuming those signals is misconfigured or missing, compliant devices and non-compliant devices get treated identically.
The blast radius of an identity misconfiguration is disproportionate to the change that caused it. A single toggle on a single policy can expose your entire user population. And unlike a misconfigured Intune compliance policy — which affects enrolled devices and generates visible non-compliance in the portal — a broken Conditional Access policy is invisible until someone tries to access a resource and either gets blocked when they shouldn't, or more dangerously, gets through when they shouldn't.
What the official Microsoft documentation doesn't tell you clearly enough:
- The Entra audit log is not a recovery tool. It records what changed but does not give you a one-click restore. Reconstructing policy state from audit log entries requires interpreting JSON diffs manually, and those diffs are not always complete for complex nested conditions.
- Conditional Access policies have implicit dependencies. Named Locations, Authentication Strengths, Terms of Use, and Custom Security Attributes are all referenced by policies but backed up separately — or not at all — if you're doing this manually. A restore that misses a Named Location reference leaves you with a broken policy that silently fails to evaluate correctly.
- Entra ID has no native "undo" button. This sounds obvious but catches people off guard. The expectation set by consumer software and even other enterprise platforms doesn't apply here. Without a deliberate backup strategy, rollback means manual reconstruction.
- Licensing requirements matter. Full Entra Backup and Recovery capabilities, particularly the automated scheduled backup and the guided recovery experience, require Microsoft Entra ID P2 or the equivalent through an E5 or Entra Suite license. P1 alone is insufficient for the full feature set.
From a compliance perspective, frameworks like ISO 27001, SOC 2, and NIST CSF all have explicit requirements around configuration management and recovery capability for critical systems. Identity infrastructure qualifies. Auditors are increasingly asking for evidence of identity configuration backup procedures, and "we export it manually sometimes" is not a defensible answer.
Root Cause Analysis
To understand what Entra Backup and Recovery actually protects — and what it doesn't — you need to understand the object model it operates on. Under the hood, the feature is built on top of the Microsoft Graph API's representation of your Entra tenant configuration. The backup process takes point-in-time snapshots of specific resource types and stores them as versioned configuration exports that can be compared, diffed, and restored through the portal or programmatically.
The resource types currently covered by automated backup include:
- Conditional Access Policies (
microsoft.graph.conditionalAccessPolicy) - Named Locations (
microsoft.graph.namedLocationand subtypes) - Authentication Strengths (
microsoft.graph.authenticationStrength) - Cross-Tenant Access Settings
- Authentication Methods Policies
What's not yet in scope for the managed backup: App Registrations, Enterprise Application configurations, custom roles, and PIM role assignments. These are still your responsibility to export independently.
Before Entra Backup and Recovery was available, the standard approach was to script exports via Graph API and store them in source control. Here's a representative PowerShell block we used in production — and still use as a secondary validation layer — to capture Conditional Access policy state:
# Requires Microsoft.Graph.Identity.SignIns module # Connect with appropriate scopes Connect-MgGraph -Scopes "Policy.Read.All", "Policy.ReadWrite.ConditionalAccess" # Export all Conditional Access policies to JSON $policies = Get-MgIdentityConditionalAccessPolicy -All $exportPath = "C:\EntraBackup\CA_$(Get-Date -Format 'yyyyMMdd_HHmmss').json" $policies | ConvertTo-Json -Depth 20 | Out-File -FilePath $exportPath Write-Host "Exported $($policies.Count) policies to $exportPath" # Export Named Locations $locations = Get-MgIdentityConditionalAccessNamedLocation -All $locExportPath = "C:\EntraBackup\NamedLocations_$(Get-Date -Format 'yyyyMMdd_HHmmss').json" $locations | ConvertTo-Json -Depth 20 | Out-File -FilePath $locExportPath Write-Host "Exported $($locations.Count) named locations to $locExportPath"
The problem with this approach alone is that it's only as good as the last time someone ran it. In a busy environment, configuration changes happen continuously. A manual or even scheduled export might be 24 hours stale when you need it. The Entra Backup and Recovery feature addresses this with automated, scheduled backups that run independently of any admin action — which is the critical operational difference.
To query current backup status and available restore points via Graph API, you can use the backup configuration endpoint. At the time of writing, this is available in the beta endpoint:
# Query available backup configurations
$uri = "https://graph.microsoft.com/beta/directory/backupRestore/oneDriveForBusinessRestoreSession"
# For Entra-specific backup status (identity configuration backups)
$entraBackupUri = "https://graph.microsoft.com/beta/directory/backupRestore"
$headers = @{
"Authorization" = "Bearer $accessToken"
"Content-Type" = "application/json"
}
$response = Invoke-RestMethod -Uri $entraBackupUri -Headers $headers -Method Get
$response | ConvertTo-Json -Depth 10
The audit trail for backup and restore operations flows through the Entra audit log under the Directory Management category, with operation names prefixed with BackupRestore. You can query these directly:
# Query audit logs for backup/restore activity
Get-MgAuditLogDirectoryAudit -Filter "category eq 'DirectoryManagement' and startswith(activityDisplayName,'BackupRestore')" -Top 50 |
Select-Object ActivityDateTime, ActivityDisplayName, Result, InitiatedBy |
Format-Table -AutoSize
The Solution
Implementing Entra Backup and Recovery properly involves three distinct workstreams: enabling and configuring the automated backup, establishing a validation cadence, and documenting and rehearsing the recovery procedure. All three matter. The third one especially — untested recovery procedures are not recovery procedures.
Step 1: Enable Automated Backup
In the Entra admin center, navigate to Identity > Overview > Backup and Recovery (Preview). From there you configure backup frequency (daily is the current default and minimum recommended interval), retention period, and the scope of resource types to include. Enable all available resource types — there is no meaningful cost or performance reason to exclude any of them, and the completeness of your backup directly determines the completeness of your recovery.
Assign the Global Administrator or Security Administrator role to the identity that will manage backup and recovery operations. Note that reading backup configurations requires at minimum Global Reader, but executing a restore requires elevated permissions. Structure your PIM assignments accordingly — restore operations should be Just-in-Time, not standing access.
Step 2: Supplemental Export via Pipeline
Don't rely solely on the portal-managed backup. Implement a supplemental automated export that commits configuration JSON to a Git repository. This gives you version history, diff visibility, and a configuration-as-code foundation for future deployments. Here's the core of what we run as a scheduled Azure Automation runbook:
# Azure Automation Runbook: Export-EntraConfigToGit
# Managed Identity requires: Policy.Read.All, Directory.Read.All
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Identity.SignIns
Import-Module Microsoft.Graph.Identity.DirectoryManagement
Connect-MgGraph -Identity
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$outputBase = "$env:TEMP\EntraExport_$timestamp"
New-Item -ItemType Directory -Path $outputBase -Force | Out-Null
# Conditional Access Policies
$caPolicies = Get-MgIdentityConditionalAccessPolicy -All
$caPolicies | ConvertTo-Json -Depth 20 |
Out-File "$outputBase\ConditionalAccessPolicies.json" -Encoding UTF8
# Named Locations
$namedLocations = Get-MgIdentityConditionalAccessNamedLocation -All
$namedLocations | ConvertTo-Json -Depth 20 |
Out-File "$outputBase\NamedLocations.json" -Encoding UTF8
# Authentication Methods Policy
$authMethodsPolicy = Get-MgPolicyAuthenticationMethodPolicy
$authMethodsPolicy | ConvertTo-Json -Depth 20 |
Out-File "$outputBase\AuthenticationMethodsPolicy.json" -Encoding UTF8
# Output summary for runbook log
Write-Output "Export complete: $($caPolicies.Count) CA policies, $($namedLocations.Count) named locations"
Write-Output "Files written to: $outputBase"
# From here, integrate with your preferred Git commit mechanism
# (Azure DevOps REST API, GitHub Actions trigger via webhook, etc.)
Step 3: Recovery Procedure — Conditional Access Restore
When you need to recover, the Entra portal recovery experience presents available restore points with a diff view showing what changed between the current state and the selected backup. This is where the feature earns its value. You can restore individual policies rather than doing a full tenant rollback, which is critical — you rarely want to undo everything, just the thing that broke.
For environments where you need programmatic restore (disaster recovery automation, for instance), the Graph API supports restore operations. The pattern using your exported JSON as source material looks like this:
# Restore a specific Conditional Access policy from a JSON backup
# WARNING: Test in non-production first. This WILL modify live policy state.
$backupFile = "C:\EntraBackup\ConditionalAccessPolicies_20250101_120000.json"
$targetPolicyDisplayName = "Require MFA for All Users"
$policies = Get-Content $backupFile | ConvertFrom-Json
$targetPolicy = $policies | Where-Object { $_.displayName -eq $targetPolicyDisplayName }
if (-not $targetPolicy) {
Write-Error "Policy '$targetPolicyDisplayName' not found in backup file"
exit 1
}
# Get current policy ID by display name
$currentPolicy = Get-MgIdentityConditionalAccessPolicy -Filter "displayName eq '$targetPolicyDisplayName'"
if ($currentPolicy) {
# Update existing policy
$policyBody = @{
state = $targetPolicy.state
conditions = $targetPolicy.conditions
grantControls = $targetPolicy.grantControls
sessionControls = $targetPolicy.sessionControls
}
Update-MgIdentityConditionalAccessPolicy `
-ConditionalAccessPolicyId $currentPolicy.Id `
-BodyParameter ($policyBody | ConvertTo-Json -Depth 20)
Write-Host "Policy '$targetPolicyDisplayName' restored successfully" -ForegroundColor Green
} else {
Write-Warning "Policy not found in current tenant — creating new"
# New-MgIdentityConditionalAccessPolicy with full body
}
Always validate after restore. Don't assume the operation succeeded fully just because it returned no errors. Run a post-restore verification:
# Post-restore validation
$restoredPolicy = Get-MgIdentityConditionalAccessPolicy `
-Filter "displayName eq '$targetPolicyDisplayName'"
Write-Host "Policy State: $($restoredPolicy.State)"
Write-Host "Grant Controls: $($restoredPolicy.GrantControls | ConvertTo-Json -Depth 5)"
Write-Host "Conditions: $($restoredPolicy.Conditions | ConvertTo-Json -Depth 5)"
Relevant Documentation
Microsoft's official guidance is worth reading alongside this post: Microsoft Entra Backup and Recovery overview, the Conditional Access documentation, and the Graph API reference for conditionalAccessPolicy are the three references you'll return to most frequently during implementation.
Scaling Considerations
At 4,200 devices and a mid-sized policy set, the backup and recovery operations are fast — export takes seconds, portal-based restore takes under a minute for an individual policy. The calculus changes at scale, and there are specific pressure points worth planning around.
Policy count above 100: Entra tenants with large Conditional Access policy libraries (common in large enterprises with per-application policy strategies) will find the portal diff view increasingly noisy. Invest in tooling that can generate human-readable summaries of what changed between backup snapshots. The raw JSON diff is technically complete but operationally unusable when you're comparing 80-field policy objects.
Multi-geo tenants: If your organization operates across multiple Entra tenants (common in large enterprises with subsidiary structures or regulated data residency requirements), each tenant requires its own backup configuration. There is no cross-tenant backup federation. Build your automation and monitoring to account for N tenants, not one.
Break-glass accounts: Your break-glass (emergency access) accounts should be explicitly excluded from any Conditional Access restore operation that touches MFA or compliant device requirements. During a recovery scenario, the last thing you want is to restore a policy that locks out the accounts you need to complete the recovery. Document this exclusion explicitly in your runbooks.
Change velocity: In environments with high change velocity — active Conditional Access policy development, frequent Named Location updates — daily backup frequency may not provide sufficient granularity. Supplement with event-driven exports triggered by audit log alerts on policy modification events. Microsoft Sentinel or a Logic App connected to the Entra audit log stream can trigger a backup export within minutes of any policy change.
Restore testing at scale: Don't test restore procedures only in production-scale scenarios. Maintain a dedicated test tenant with a representative (not necessarily complete) copy of your policy configuration where you can rehearse restore operations without risk. The muscle memory of executing a restore under pressure is different from reading a runbook for the first time during an incident.
Lessons Learned
- Backup without a tested recovery procedure is theater. We had exports. We'd never actually restored from them before the incident. The first time we ran through the restore process was during an active security event with stakeholders watching. That is not the time to discover that your JSON export is missing the
sessionControlsblock because the cmdlet version you were using had a serialization bug. Run quarterly restore drills. Document them. Make them boring. - Named Locations are the silent dependency that breaks restores. When you restore a Conditional Access policy that references a Named Location by GUID, and that Named Location was also modified or deleted, the policy restores but evaluates incorrectly. The portal doesn't warn you. The policy shows as enabled and configured. The conditions just don't work as expected. Always restore Named Locations before restoring the policies that reference them, and validate the GUIDs match.
- Audit log coverage is not backup coverage. Several times during post-incident reviews, teams have confused "we can see the change in the audit log" with "we can recover from this." They are completely different things. The audit log tells you what changed. A backup tells you what to restore it to. Treat them as complementary, not interchangeable.
- Scope down who can modify Conditional Access policies using PIM. The incident that triggered our investment in backup and recovery was caused by an admin with standing GA rights making a change without a second reviewer. After implementing Entra Backup and Recovery, we also implemented PIM-gated access for Conditional Access policy modifications and required a ticket number in the justification field. The backup capability is your safety net. PIM scoping is what reduces how often you need it.
- The feature is still maturing — architect for the gaps. Entra Backup and Recovery doesn't yet cover App Registrations, Enterprise Applications, or custom role definitions. These are high-value targets for misconfiguration and equally high-impact if lost. Until coverage expands, maintain separate export automation for these object types and version them in source control. Don't assume that because backup and recovery is enabled, your entire identity configuration is protected.