All scripts
Governance 264

Backup-ConditionalAccessPolicies

Exports every Conditional Access policy in the tenant to timestamped JSON, conditions, grant controls, and all. Run it before touching CA policies so you always have a rollback point.

Backup-ConditionalAccessPolicies.ps1
<#
.SYNOPSIS
    Backup-ConditionalAccessPolicies.ps1 - Snapshots all Conditional Access policies to JSON.

.DESCRIPTION
    Exports every Conditional Access policy (conditions, grant controls, session
    controls, state) to a timestamped JSON file before you make changes. Requires
    Graph scope: Policy.Read.All

.AUTHOR
    Shehryar Hassan

.EXAMPLE
    .\Backup-ConditionalAccessPolicies.ps1 -OutputPath ".\ca-backup.json"
#>

param(
    [Parameter(Mandatory=$false)]
    [string]$OutputPath = ".\ca-backup-$(Get-Date -Format 'yyyyMMdd-HHmmss').json"
)

Write-Host "=============================================" -ForegroundColor Cyan
Write-Host "  Conditional Access Policy Backup" -ForegroundColor Cyan
Write-Host "=============================================" -ForegroundColor Cyan

if (-not (Get-MgContext)) {
    Write-Host "[INFO] Connecting to Microsoft Graph..." -ForegroundColor Yellow
    Connect-MgGraph -Scopes "Policy.Read.All"
}

$policies = Get-MgIdentityConditionalAccessPolicy -All

$snapshot = [PSCustomObject]@{
    CapturedAt   = (Get-Date).ToString("o")
    PolicyCount  = $policies.Count
    Policies     = $policies
}

$snapshot | ConvertTo-Json -Depth 10 | Out-File -FilePath $OutputPath -Encoding utf8

Write-Host "[SUCCESS] $($policies.Count) polic$(if ($policies.Count -eq 1) { 'y' } else { 'ies' }) backed up to: $OutputPath" -ForegroundColor Green
$disabled = $policies | Where-Object State -eq "disabled"
if ($disabled) {
    Write-Host "[INFO] $($disabled.Count) polic$(if ($disabled.Count -eq 1) { 'y is' } else { 'ies are' }) currently disabled:" -ForegroundColor Yellow
    $disabled | Format-Table DisplayName, State -AutoSize
}

Read it before you run it, and test in a safe tenant first.