Audit Deleted Conditional Access Policies Using Graph PowerShell

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.


The Script: Query “Delete policy” Events

# 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
}
                                

How the Script Works

  1. Graph Authentication
  2. The script starts by authenticating with Microsoft Graph using:

    Connect-MgGraph -Scopes "AuditLog.Read.All"

    This scope is mandatory for retrieving audit logs.

  3. Define Time Window
  4. 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.

  5. Filtering “Delete policy” Events
  6. The OData filter is crafted to retrieve only:

    • Category: Policy
    • Activity: Delete policy
    • Time range: greater than or equal to $startTime in UTC format
  7. Display Output
  8. For each log entry, the script displays:

    • Deleted Time – When the deletion occurred
    • Deleted Policy – Name of the removed policy
    • Deleted By – Admin UPN who performed the action
    • Result Status – Success or failure of the deletion

The output is formatted into a clean table for review or export.


Further Enhancements

  • Export to CSV
  • $output | Export-Csv -Path "DeletedCAPolicies.csv" -NoTypeInformation
  • Filter by Admin
  • $output | Where-Object { $_."Deleted By (Admin UPN)" -eq "admin@domain.com" }
  • Search by Policy Name
  • $output | Where-Object { $_."Deleted Policy" -like "*legacy*" }
  • Include All Policy Events (Add, Update, Delete)
  • Modify the filter to:

    $filter = "category eq 'Policy' and activityDateTime ge $startTime"

Possible Errors & Solutions

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

Use Cases

  • Security Auditing: Know exactly who deleted a Conditional Access policy and when.
  • Compliance Reporting: Maintain an audit trail for regulatory requirements.
  • Change Management: Ensure deletions align with approved governance workflows.
  • Investigation Support: Identify if a policy was intentionally or accidentally removed during an incident.

Conclusion

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.


Graph PowerShell Explorer Widget

20 Graph PowerShell cmdlets with easily accessible "working" examples.


Permission Required

Example:


                


                


                

© m365corner.com. All Rights Reserved. Design by HTML Codex