Invoke-EntraConditionalAccessCheck.ps1 is a PowerShell 7+ script designed to analyze Azure Entra ID Conditional Access policies to identify security gaps, exclusions, and misconfigurations. This tool is part of the EvilMist toolkit and helps security teams assess the effectiveness of their Conditional Access policy coverage and identify potential attack vectors.
Conditional Access policies are critical security controls that enforce access requirements based on conditions. This script helps:
- Security Auditors: Identify policy gaps and exclusions that could be exploited
- Penetration Testers: Discover users, groups, and applications excluded from security controls
- IT Administrators: Audit Conditional Access policy coverage and MFA enforcement
- Compliance Teams: Generate reports for security policy governance
- ✅ PowerShell 7+ Compatible: Modern PowerShell for cross-platform support
- ✅ Multiple Authentication Methods: Supports Azure CLI, Azure PowerShell, and interactive auth
- ✅ Comprehensive Policy Analysis: Enumerates all CA policies and analyzes configurations
- ✅ Exclusion Detection: Identifies users, groups, roles, and applications excluded from policies
- ✅ MFA Enforcement Gaps: Detects policies without MFA requirements
- ✅ Critical App Coverage: Checks if critical applications are protected by policies
- ✅ Legacy Auth Detection: Identifies policies targeting legacy authentication methods
- ✅ Risk Assessment: Categorizes policies by risk level (CRITICAL/HIGH/MEDIUM/LOW)
- ✅ Conflict Detection: Identifies redundant or conflicting policies
- ✅ Coverage Gap Analysis: Highlights areas without policy protection
- ✅ Stealth Mode: Configurable delays and jitter to avoid detection
- ✅ Export Options: CSV and JSON export formats
- ✅ Matrix View: Table format with analytics for quick visual scanning
- ✅ Filtering Options: Show only policies with exclusions or MFA gaps
The script checks if policies cover the following 10 critical enterprise applications:
-
Microsoft Azure Management (
797f4846-ba00-4fd7-ba43-dac1f8f63013)- Azure Resource Manager API
- Full infrastructure control capabilities
-
Azure Portal (
c44b4083-3bb0-49c1-b47d-974e53cbdf3c)- Web-based Azure infrastructure management
- Resource creation, configuration, monitoring
-
Microsoft 365 Admin Portal (
618dd325-23f6-4b6f-8380-4df78026e39b)- Web-based Microsoft 365 tenant administration
- User creation, role assignments, license management
-
Azure AD PowerShell (
1b730954-1685-4b74-9bfd-dac224a7b894)- Classic Azure AD PowerShell module
- Comprehensive directory management capabilities
-
Microsoft Azure PowerShell (
1950a258-227b-4e31-a9cf-717495945fc2)- Modern Azure PowerShell Az module
- Manages Azure resources and services
-
Microsoft Graph Command Line Tools (
14d82eec-204b-4c2f-b7e8-296a70dab67e)- Microsoft Graph CLI (mg cli)
- Programmatic access to all Microsoft 365 data
-
Office 365 Exchange Online (
00000002-0000-0ff1-ce00-000000000000)- Email and calendar service access
- Mailbox access, mail flow rules, transport settings
-
Office 365 SharePoint Online (
00000003-0000-0ff1-ce00-000000000000)- Document management and collaboration platform
- Access to all document libraries and sites
-
Microsoft Graph (
00000003-0000-0000-c000-000000000000)- Core Microsoft Graph API
- Programmatic access to Microsoft 365 data
- MS-PIM (Privileged Identity Management) (
01fc33a7-78ba-4d2f-a4b7-768e336e890e)- Just-in-time privileged access management
- Can activate elevated roles (Global Admin, etc.)
-
PowerShell 7+
- Download: https://aka.ms/powershell-release?tag=stable
- The script will check and warn if older version is detected
-
Microsoft Graph PowerShell SDK
Install-Module Microsoft.Graph -Scope CurrentUser
Or install individual modules:
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser Install-Module Microsoft.Graph.Identity.SignIns -Scope CurrentUser
The script requires the following Microsoft Graph API permissions:
-
Primary Scopes (preferred):
Policy.Read.All- Read Conditional Access policies (REQUIRED)Directory.Read.All- Read directory dataApplication.Read.All- Read application informationUser.Read.All- Read user profiles (for exclusion resolution)
-
Fallback Scopes (if full access unavailable):
Policy.Read.All- Read Conditional Access policies (REQUIRED)Directory.Read.All- Read directory data
Note: Policy.Read.All is required to enumerate Conditional Access policies. Without this permission, the script cannot function.
# Analyze all Conditional Access policies
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1# Export to CSV
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -ExportPath "ca-policies.csv"
# Export to JSON
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -ExportPath "ca-results.json"# Scan all policies including disabled ones
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -IncludeDisabled -ExportPath "all-policies.csv"# Filter to show only policies with exclusions
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -OnlyWithExclusions
# Matrix view with exclusions filter
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -OnlyWithExclusions -Matrix# Filter to show only policies without MFA requirement
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -OnlyMFAgaps
# Matrix view with MFA gaps filter
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -OnlyMFAgaps -Matrix# Display results in compact matrix format
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -Matrix
# Matrix view with export
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -Matrix -ExportPath "results.csv"# Use Azure CLI cached credentials
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -UseAzCliToken
# Use Azure PowerShell cached credentials
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -UseAzPowerShellToken
# Specify tenant
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -TenantId "your-tenant-id"# Enable stealth mode with default settings (500ms delay + 300ms jitter)
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -EnableStealth
# Stealth mode with minimal output
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -EnableStealth -QuietStealth
# Custom delay and jitter
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -RequestDelay 1.5 -RequestJitter 0.5
# Maximum stealth with custom retry
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -EnableStealth -MaxRetries 5 -QuietStealth# Comprehensive audit: all policies including disabled, with export
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -IncludeDisabled -Matrix -ExportPath "full-audit.csv"
# Security focus: policies with exclusions only
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -OnlyWithExclusions -Matrix -ExportPath "exclusions-audit.csv"
# MFA gap analysis
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -OnlyMFAgaps -Matrix -ExportPath "mfa-gaps.csv"
# Stealth reconnaissance with Azure CLI token
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -UseAzCliToken -EnableStealth -QuietStealth -ExportPath "recon.json"| Parameter | Type | Description | Default |
|---|---|---|---|
-ExportPath |
String | Path to export results (CSV or JSON based on extension) | None |
-TenantId |
String | Optional Tenant ID. Uses home tenant if not specified | None |
-UseAzCliToken |
Switch | Try to use Azure CLI cached token first | False |
-UseAzPowerShellToken |
Switch | Try to use Azure PowerShell cached token first | False |
-IncludeDisabled |
Switch | Include disabled policies in results | False |
-OnlyWithExclusions |
Switch | Show only policies with exclusions | False |
-OnlyMFAgaps |
Switch | Show only policies without MFA enforcement | False |
-Matrix |
Switch | Display results in matrix/table format | False |
| Parameter | Type | Range | Description | Default |
|---|---|---|---|---|
-EnableStealth |
Switch | - | Enable stealth mode with default delays (500ms + 300ms jitter) | False |
-RequestDelay |
Double | 0-60 | Base delay in seconds between API requests | 0 |
-RequestJitter |
Double | 0-30 | Random jitter range in seconds (+/-) | 0 |
-MaxRetries |
Int | 1-10 | Maximum retries on throttling (429) responses | 3 |
-QuietStealth |
Switch | - | Suppress stealth-related status messages | False |
The script provides detailed information about each Conditional Access policy:
[CRITICAL] Block Legacy Authentication
Policy ID: 12345678-1234-1234-1234-123456789012
State: Disabled
Risk Reasons: Policy disabled
MFA Required: No
Exclusions: 5 user(s), 2 group(s)
Includes: All users
Covers Critical Apps: No
Created: 2024-01-15T10:30:00Z
Risk Status Policy Name MFA Exclusions Critical Apps Legacy Auth Blocks
---- ------ ----------- --- ---------- -------------- ------------ ------
CRITICAL Disabled Block Legacy Authentication No 5 user(s), 2 group(s) No Yes No
HIGH Enabled Require MFA for Admins Yes 1 user(s) Yes No No
MEDIUM Enabled Require Compliant Device Yes None No No No
LOW Enabled Baseline Protection Yes None Yes No No
The script provides comprehensive statistics:
[SUMMARY]
Total policies analyzed: 12
- CRITICAL risk: 2
- HIGH risk: 3
- MEDIUM risk: 4
- LOW risk: 3
[POLICY GAPS]
Policies with exclusions: 5
Policies without MFA requirement: 3
Disabled policies: 2
Policies covering critical apps: 8
[EXCLUSIONS SUMMARY]
Unique excluded users: 15
Unique excluded groups: 8
Unique excluded roles: 2
Unique excluded apps: 3
The script assigns risk levels based on policy configuration and security posture:
| Risk Level | Criteria | Color | Recommendation |
|---|---|---|---|
| CRITICAL | Disabled policy OR no MFA requirement with exclusions | Red | IMMEDIATE ACTION REQUIRED: Enable policy or add MFA requirement |
| HIGH | Has exclusions OR no MFA requirement OR targets legacy auth | Yellow | REVIEW REQUIRED: Review exclusions and add MFA requirement |
| MEDIUM | No user targeting (all users) OR no device requirement | Cyan | CONSIDER: Refine targeting and add device requirements |
| LOW | Properly configured with MFA and appropriate targeting | Green | MONITOR: Acceptable configuration |
IF policy is disabled:
RISK = CRITICAL
ELSE IF no MFA required AND has exclusions:
RISK = CRITICAL
ELSE IF has exclusions:
RISK = HIGH
ELSE IF no MFA required:
RISK = HIGH
ELSE IF targets legacy auth:
RISK = HIGH
ELSE IF no user targeting (all users):
RISK = MEDIUM
ELSE IF no device requirement:
RISK = MEDIUM
ELSE:
RISK = LOW
IMPORTANT: Exclusions in Conditional Access policies create security gaps that can be exploited:
| Exclusion Type | Risk | Example Attack Vector |
|---|---|---|
| User Exclusions | HIGH | Admin accounts excluded from MFA requirement |
| Group Exclusions | HIGH | Security group excluded from device compliance |
| Role Exclusions | CRITICAL | Global Administrators excluded from all policies |
| Application Exclusions | MEDIUM-HIGH | Critical apps excluded from MFA requirement |
- Bypass Security Controls: Excluded entities are not subject to policy requirements
- Privilege Escalation: Excluded admin accounts can bypass MFA requirements
- Attack Surface: Exclusions create predictable security gaps
- Compliance Violations: Exclusions may violate security policies
-
Emergency Break-Glass Accounts
- Legitimate use case but should be monitored
- Should have additional compensating controls
-
Service Accounts
- Often excluded from MFA policies
- Should use managed identities or certificate-based auth
-
Legacy Applications
- Excluded due to compatibility issues
- Should be migrated or replaced
-
Administrative Roles
- Sometimes excluded for convenience
- CRITICAL RISK: Should never be excluded
Policies without MFA requirements create security vulnerabilities:
- Credential Attacks: Accounts protected only by passwords
- Phishing Susceptibility: No second factor to prevent account takeover
- Compliance Violations: May violate security policies requiring MFA
- Privilege Escalation: Admin accounts without MFA are high-value targets
Policies should protect critical applications:
- Management Tools: Azure Portal, M365 Admin Portal, PowerShell tools
- Core Services: Exchange Online, SharePoint Online, Microsoft Graph
- Identity Management: PIM, Azure AD management
Gap Analysis: If critical apps are not covered by policies, they may be accessible without security controls.
Policies targeting legacy authentication methods are important but risky:
- Legacy Auth: Exchange ActiveSync, IMAP, POP3, SMTP
- Security Risk: Legacy protocols often don't support modern security features
- Recommendation: Block legacy auth entirely where possible
Multiple policies can create conflicts:
- Conflicting Requirements: One policy requires MFA, another blocks access
- Redundant Policies: Multiple policies applying same controls
- Order Dependency: Policy evaluation order matters
- Regular Audits: Run monthly to track policy changes and exclusions
- Exclusion Review: Review all exclusions quarterly and document justification
- MFA Enforcement: Ensure all policies require MFA for privileged access
- Critical App Coverage: Verify all critical applications are protected
- Documentation: Maintain records of policy purpose and exclusions
- Initial Reconnaissance: Identify policies and exclusions
- Target Selection: Prioritize excluded users/groups/roles
- Attack Path Analysis: Use exclusions to bypass security controls
- Gap Exploitation: Exploit policies without MFA requirements
- Stealth Operations: Use
-EnableStealthto avoid detection
- Documentation: Export results regularly for audit trails
- Policy Alignment: Verify policies align with security requirements
- Trend Analysis: Compare results over time
- Remediation Tracking: Monitor exclusion reduction and MFA adoption
- Access Reviews: Use reports for quarterly policy certification
Includes all fields for analysis:
- PolicyId, DisplayName, State
- CreatedDateTime, ModifiedDateTime
- RiskLevel, RiskReasons
- ExcludeUsersCount, ExcludeGroupsCount, ExcludeRolesCount, ExcludeAppsCount
- ExclusionSummary
- IncludeUsersCount, IncludeGroupsCount, IncludeRolesCount, IncludeAppsCount
- MFARequired, RequireCompliantDevice, RequireHybridAzureADJoinedDevice
- RequireApprovedClientApp, RequireAppProtectionPolicy
- BlocksAccess, TargetsLegacyAuth, ClientAppTypes
- CoversCriticalApps, CoveredCriticalApps
- ExcludeLocationsCount, IncludeLocationsCount
- IncludePlatforms, ExcludePlatforms
Structured format for automation:
[
{
"PolicyId": "12345678-1234-1234-1234-123456789012",
"DisplayName": "Require MFA for Admins",
"State": "enabled",
"RiskLevel": "HIGH",
"RiskReasons": "Has exclusions (1 user(s))",
"ExcludeUsersCount": 1,
"ExcludeGroupsCount": 0,
"MFARequired": true,
"CoversCriticalApps": true,
"CoveredCriticalApps": "Microsoft Azure Management, Azure Portal"
}
]Cause: No policies exist in the tenant or insufficient permissions.
Solution:
- Verify
Policy.Read.Allpermission is granted - Check if policies exist in Azure AD portal
- Ensure you're querying the correct tenant
Cause: Insufficient Graph API permissions.
Solution:
# Disconnect and reconnect with proper scopes
Disconnect-MgGraph
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1
# Accept permission consent when promptedCause: Missing or outdated Microsoft.Graph modules.
Solution:
# Update all Graph modules
Update-Module Microsoft.Graph -Force
# Or reinstall
Uninstall-Module Microsoft.Graph -AllVersions
Install-Module Microsoft.Graph -Scope CurrentUserCause: Large number of policies or throttling.
Solution:
# Use stealth mode to handle throttling
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -EnableStealth -MaxRetries 5
# Or reduce load with filtering
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -OnlyWithExclusions# Identify all policies and their security posture
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -Matrix -ExportPath "audit_$(Get-Date -Format 'yyyy-MM-dd').csv"Output: CSV file with all policies, risk levels, and security gaps.
# Find policies with exclusions
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -OnlyWithExclusions -Matrix
# Review output, then remediateUse Case: Identify security gaps from policy exclusions.
# Find policies without MFA requirement
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -OnlyMFAgaps -MatrixUse Case: Identify policies that don't enforce MFA.
# Stealth mode scan using existing Azure CLI token
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -UseAzCliToken -EnableStealth -QuietStealth -ExportPath "targets.json"Use Case: Silent enumeration of policy gaps during engagement.
# Monthly audit including disabled policies
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -IncludeDisabled -Matrix -ExportPath "compliance_report.csv"
# Compare with previous month's reportUse Case: Track policy changes and exclusion trends over time.
# Schedule weekly scans
$scheduledScript = {
$date = Get-Date -Format "yyyy-MM-dd"
$path = "C:\SecurityAudits\CAPolicies_$date.csv"
C:\Tools\Invoke-EntraConditionalAccessCheck.ps1 -Matrix -ExportPath $path
# Send alert if critical risks found
$results = Import-Csv $path
$criticalRisk = $results | Where-Object { $_.RiskLevel -eq "CRITICAL" }
if ($criticalRisk.Count -gt 0) {
Send-MailMessage -To "security@company.com" `
-Subject "ALERT: $($criticalRisk.Count) critical CA policy risks found" `
-Body "Review attached report." `
-Attachments $path `
-SmtpServer "smtp.company.com"
}
}
# Create scheduled task (run as admin)
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 6am
$action = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument "-File C:\Scripts\WeeklyCAPolicyCheck.ps1"
Register-ScheduledTask -TaskName "Weekly CA Policy Audit" -Trigger $trigger -Action $action# Export JSON for SIEM ingestion
.\scripts\powershell\Invoke-EntraConditionalAccessCheck.ps1 -ExportPath "siem_feed.json"
# Post-process for your SIEM format
$results = Get-Content "siem_feed.json" | ConvertFrom-Json
$siemEvents = $results | ForEach-Object {
@{
timestamp = (Get-Date).ToString("o")
event_type = "conditional_access_policy"
severity = $_.RiskLevel
policy_name = $_.DisplayName
policy_id = $_.PolicyId
state = $_.State
has_exclusions = ($_.ExcludeUsersCount + $_.ExcludeGroupsCount + $_.ExcludeRolesCount + $_.ExcludeAppsCount) -gt 0
mfa_required = $_.MFARequired
covers_critical_apps = $_.CoversCriticalApps
}
}
$siemEvents | ConvertTo-Json | Out-File "siem_formatted.json"- Initial implementation
- Support for Conditional Access policy enumeration
- Exclusion detection (users, groups, roles, apps)
- MFA enforcement gap detection
- Critical application coverage analysis
- Risk assessment based on gaps and exclusions
- Matrix view and export capabilities
- Stealth mode with configurable delays
- Multiple authentication methods
- Comprehensive policy analytics
This script is part of the EvilMist toolkit.
Copyright (C) 2025 Logisek
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
See the LICENSE file for more details.
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
Visit: https://github.com/Logisek/EvilMist
For questions, issues, or feature requests:
- GitHub Issues: https://github.com/Logisek/EvilMist/issues
- Email: info@logisek.com
- Website: https://logisek.com
- Invoke-EntraRecon.ps1: Comprehensive Azure AD reconnaissance
- Invoke-EntraMFACheck.ps1: MFA compliance audit
- Invoke-EntraGuestCheck.ps1: Guest account security analysis
- Invoke-EntraAppAccess.ps1: Critical administrative access audit
- Invoke-EntraRoleCheck.ps1: Privileged role assignment audit
- Invoke-EntraServicePrincipalCheck.ps1: Service principal security audit