Conditional Access (CA) policies are at the core of securing access in Microsoft 365. While creating and updating policies is essential for evolving security needs, deleting a policy is a high-impact action that must be carefully tracked.
Fortunately, Azure AD logs every policy deletion under the “Policy” category with the activity name “Delete policy.” Using Microsoft Graph PowerShell, you can extract these events, determine who deleted the policy, and when the action occurred, all in a matter of seconds.
This article introduces a PowerShell script that helps you maintain visibility over deleted CA policies for governance, security, and compliance purposes.
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "AuditLog.Read.All"
# Define the lookback window (change as needed)
$daysToLookBack = 14
$startTime = (Get-Date).AddDays(-$daysToLookBack).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
# Build OData filter for "Delete policy" event under "Policy" category
$filter = "category eq 'Policy' and activityDisplayName eq 'Delete policy' and activityDateTime ge $startTime"
# Retrieve the audit logs
$logs = Get-MgAuditLogDirectoryAudit -Filter $filter -All
# Parse and display relevant data
$output = foreach ($log in $logs) {
$policyName = ($log.targetResources | Select-Object -First 1).displayName
$adminUser = $log.initiatedBy.user.userPrincipalName
[PSCustomObject]@{
"Deleted Time" = $log.activityDateTime
"Deleted Policy" = $policyName
"Deleted By (Admin UPN)" = $adminUser
"Result Status" = $log.result
}
}
# Output to console
if ($output) {
$output | Format-Table -AutoSize
} else {
Write-Host "No 'Delete policy' events found in the last $daysToLookBack days." -ForegroundColor Yellow
}
The script starts by authenticating with Microsoft Graph using:
Connect-MgGraph -Scopes "AuditLog.Read.All"
This scope is mandatory for retrieving audit logs.
You can set the lookback window using the $daysToLookBack variable. The default is 14 days, but it can be adjusted based on your auditing requirements.
The OData filter is crafted to retrieve only:
For each log entry, the script displays:
The output is formatted into a clean table for review or export.
$output | Export-Csv -Path "DeletedCAPolicies.csv" -NoTypeInformation
$output | Where-Object { $_."Deleted By (Admin UPN)" -eq "admin@domain.com" }
$output | Where-Object { $_."Deleted Policy" -like "*legacy*" }
Modify the filter to:
$filter = "category eq 'Policy' and activityDateTime ge $startTime"
Error | Cause | Solution |
Invalid filter clause | Incorrect date format | Use ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") |
Access denied | Missing permission | Ensure AuditLog.Read.All is granted and consented |
No audit logs found | Wrong filter or too narrow date range | Extend $daysToLookBack or double-check filter values |
Deleting a Conditional Access policy is a serious action that can weaken an organization’s security posture if done improperly. By leveraging this Graph PowerShell script, you can track all such deletions, identify the responsible administrators, and integrate this audit into your broader security and compliance efforts.
Whether you're preparing for an audit or enforcing internal controls, this script gives you the insight and accountability you need to manage your Conditional Access policies effectively.
© m365corner.com. All Rights Reserved. Design by HTML Codex