Every account excluded from a Conditional Access policy is an account that policy does not protect, and exclusion lists grow quietly until a user-type service account with a password becomes the easiest way into the tenant. Microsoft's own guidance lists the problems: exclusions built from user lists give little visibility, people may not know they are excluded, anyone who can join an exclusion group bypasses the policy, and lists rarely shrink. This runbook shows how to inventory every exclusion in Microsoft Entra ID with Microsoft Graph, find the sign-ins that no policy covered, decide what to do with each excluded account, and put the survivors under a recurring access review. It is for identity engineers and security teams who own Conditional Access. For policy design itself, see the Conditional Access Guide.
This is an independent guide from NHI Mgmt Group, based on Microsoft's public documentation as of November 2026. It is not sponsored or reviewed by Microsoft. Product features change, so confirm settings against Microsoft's current documentation.
Key takeaways
- Read exclusions from the policies, not from memory.
GET /identity/conditionalAccess/policiesreturnsexcludeUsers,excludeGroups,excludeRolesandexcludeGuestsOrExternalUsersfor every policy. - Expand groups and roles to people. An excluded group is only as small as its transitive membership; resolve it with
/groups/{id}/transitiveMembers. - Check what actually happened at sign-in.
SigninLogsrows withConditionalAccessStatus == "notApplied"show successful sign-ins no policy touched; the Conditional Access gap analyzer workbook summarises them. - User accounts used as service accounts are the main target. Microsoft recommends moving them to workload identities (managed identities or service principals), which can be covered by Conditional Access for workload identities.
- Keep exclusions in one reviewed group per purpose. An assigned security group plus a recurring access review gives you evidence and a shrinking list.
When you need this
Run the review before you switch a report-only policy on, after any migration from per-user MFA, ahead of an audit, and on a fixed cycle (quarterly is our suggestion). Typical exclusion debt includes scripting accounts that sign in with a user name and password, scanner and printer accounts, shared mailboxes used for SMTP, "temporary" vendor groups, executives who objected to prompts, travellers excluded from location blocks, and accounts left out of a legacy authentication block. An attacker who sprays passwords (ATT&CK T1110.003) succeeds against exactly these accounts and then holds a valid cloud account (T1078.004). See the Password Spraying and Credential Stuffing Defence Guide.
Before you start
- Read access:
Policy.Read.Allfor Conditional Access policies andGroupMember.ReadBasic.Allfor group membership, delegated or application. A Global Reader or Security Reader role covers portal reading. - Logs: sign-in logs exported to a Log Analytics workspace through diagnostic settings, for the KQL and the gap analyzer workbook. The workbook requires Microsoft Entra ID P1.
- Change roles: Conditional Access Administrator to change policies; Identity Governance Administrator or User Administrator to create access reviews, which require Microsoft Entra ID P2, Microsoft Entra ID Governance or EMS E5.
- Emergency access accounts: know their object IDs and the group that holds them, so they are recognised and left alone.
Step-by-step
1. Export every policy's user scope
Call GET https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies (in Microsoft Graph PowerShell, Get-MgIdentityConditionalAccessPolicy) and record for each policy: displayName, state, the grant controls, and the conditions.users object. The fields to capture are below.
| Property | Holds | What to look for |
|---|---|---|
includeUsers | User IDs or All, None, GuestsOrExternalUsers | Policies scoped to a list instead of All exclude everyone else by omission. |
excludeUsers | User IDs or GuestsOrExternalUsers | Individually excluded users: the least visible form. |
excludeGroups | Group IDs | Expand each group to transitive members. |
excludeRoles | Directory role template IDs | Everyone holding the role, now or after a later assignment. |
excludeGuestsOrExternalUsers | Guest or external user types | Whole classes of external users removed from scope. |
conditions.clientAppTypes and conditions.applications | Client and application scope | Excluded apps and client types are exclusions too, by a different route. |
Include policies in report-only state: they show what you intend to enforce, and their exclusions will apply the day you switch them on.
2. Resolve groups and roles to accounts
- For each excluded group, call
GET /groups/{id}/transitiveMembersso nested groups are counted. - For each excluded role, list current active and eligible assignments of that role.
- Build one table: account, how it is excluded (direct, group, role), from which policies, and whether those policies require MFA, block legacy authentication, block locations or require a compliant device.
- Join it to the directory: account type (member or guest), on-premises synced or cloud-only, enabled state, last successful sign-in, and assigned licences.
3. Find sign-ins no policy covered
Policy exports show intent; sign-in logs show what happened. In Log Analytics, the SigninLogs table records ConditionalAccessStatus as success, failure or notApplied, and AuthenticationRequirement as the highest level of authentication the sign-in needed.
SigninLogs
| where TimeGenerated > ago(30d)
| where ResultType == "0"
| where ConditionalAccessStatus == "notApplied" or AuthenticationRequirement == "singleFactorAuthentication"
| summarize SignIns = count(), Apps = make_set(AppDisplayName, 20), Clients = make_set(ClientAppUsed, 10), LastSeen = max(TimeGenerated) by UserPrincipalName, UserType
| order by SignIns desc
Then open the Conditional Access Gap Analyzer workbook (Entra ID, Monitoring & health, Workbooks). Its four sections cover legacy authentication sign-ins, applications not affected by Conditional Access, high-risk sign-ins that bypassed policy, and sign-ins by location that no policy affected, each broken down to user level.
4. Separate people from automation
Signals that an excluded "user" is really a service account: no interactive sign-ins, a single application, a ClientAppUsed value such as SMTP, IMAP or Exchange ActiveSync, sign-ins from a fixed server IP, a name like svc- or app-, and no manager. Microsoft's mandatory MFA documentation states that user identities used as service accounts for scripts must complete MFA once enforcement reaches them, and recommends migrating them to workload identities. See the Azure Mandatory MFA page for the timing, and confirm current dates in Microsoft's documentation.
5. Decide each exclusion
| Exclusion type | Recommended action (ours) | Where it ends up |
|---|---|---|
| Emergency access accounts | Keep excluded from policies that block or restrict sign-in, via one dedicated group; protect with a passkey (FIDO2) or certificate-based authentication; alert on every sign-in | See the Break-Glass Account Guide |
| User account running a script or Azure automation | Move to a managed identity or service principal with a certificate or federated credential; disable the user | Workload identity, optionally under Conditional Access for workload identities |
| Device or app using legacy protocols (SMTP AUTH, IMAP, POP) | Move to a modern authentication path or a scoped relay; then remove from the legacy block exclusion | See the Legacy Authentication and ROPC Retirement Guide |
| Person who objected to MFA prompts | Enrol in a phishing-resistant method and tune session controls instead of excluding | Back in scope |
| Traveller excluded from a location block | Time-limited group with an expiry, reviewed weekly | Short-lived exclusion group |
| Vendor or project group | Remove; give external users their own policy | Guest or external user policy |
| Disabled or departed account still listed | Remove from the exclusion and delete per your leaver process | Gone |
6. Move workload accounts onto workload controls
Conditional Access for workload identities covers single-tenant service principals registered in your tenant. It supports location and service principal risk conditions with a Block grant, and the service principal must be assigned to the policy directly, because groups containing service principals are not enforced. Microsoft and third-party multitenant applications and managed identities sit outside these policies; Microsoft suggests access reviews for managed identities. Workload Identities Premium licences are needed to create or change these policies. See the Service Account Security Guide for the wider lifecycle.
7. Put what remains under review
- Create one security group per exclusion purpose, membership type Assigned, named for its purpose (for example CA-Exclude-LocationBlock-Travel).
- Replace individual
excludeUsersentries with that group in each policy, testing in report-only first. - Create a recurring access review on each group. Microsoft's examples use a weekly self-attestation review for location exclusions and a recurring owner review for legacy authentication exclusions, with results auto-applied and non-responders removed.
- Restrict who can change membership of exclusion groups, since anyone who can add themselves can bypass the policy.
Verify it worked
- Re-run the export: individual
excludeUsersentries replaced by purpose groups, and each group smaller than before. - Re-run the KQL: fewer successful single-factor and
notAppliedsign-ins, and none from accounts you moved to workload identities. - Check the gap analyzer workbook sections fall towards zero outside named exceptions.
- Sign in once with each emergency access account as a drill and confirm the alert fires.
Rollback and common errors
- A process breaks after removal: add the account back to the purpose group (not to
excludeUsers), record an expiry date and open a migration ticket. - Locked out while editing: always keep the emergency access group excluded from policies that block sign-in; test in report-only and use the What If tool before enforcing.
- Nested groups missed: direct membership calls undercount; use transitive membership.
- Role exclusions: excluding a directory role silently excludes every future holder of the role; prefer a named group.
- Workload policy has no effect: the service principal was added through a group; assign it directly.
Metrics and mapping
| Metric | Source | Target (our suggestion) |
|---|---|---|
| Accounts excluded from any MFA policy, excluding emergency access | Policy export joined to group membership | Falling each review; named owner for each |
Individual excludeUsers entries | Policy export | Zero |
| Successful single-factor sign-ins per week | SigninLogs | Only known, reviewed exceptions |
| User accounts used for automation | Step 4 triage list | Zero, all moved to workload identities |
| Exclusion groups with an active access review | Access reviews list | All |
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev 5 | IA-2(1), IA-2(2), AC-2 | MFA for privileged and non-privileged accounts; reviewing account exceptions |
| NIST CSF 2.0 | PR.AA-03 | Users, services and hardware are authenticated |
| MITRE ATT&CK | T1078.004, T1110.003; mitigation M1032 | Valid cloud accounts reached through password-only paths; multi-factor authentication |
Practitioner checklist
- All Conditional Access policies exported, including report-only, with every exclusion field captured.
- Excluded groups and roles resolved to transitive members and joined to account type and last sign-in.
- KQL and the gap analyzer workbook run over at least 30 days.
- Automation accounts identified and migration to managed identities or service principals planned.
- Emergency access accounts in one group, on passkeys or certificates, with sign-in alerts.
- Individual user exclusions replaced by purpose groups with restricted membership management.
- Recurring access reviews on every exclusion group, results auto-applied.
- Review repeated on a fixed cycle and before each new policy is enforced.
Standards and references
- Microsoft Learn: Use access reviews to manage users excluded from Conditional Access policies
- Microsoft Graph: List policies (Conditional Access)
- Microsoft Graph: conditionalAccessUsers resource type
- Microsoft Learn: Conditional Access gap analyzer workbook
- Microsoft Learn: Conditional Access for workload identities
- Microsoft Learn: Manage emergency access accounts in Microsoft Entra ID
- Microsoft Learn: Mandatory multifactor authentication for Azure and admin portals
- Microsoft Learn: SigninLogs table reference
Related NHI Mgmt Group resources: Conditional Access Guide, Entra Per-User MFA to Conditional Access, Break-Glass Account Guide, Service Account Security Guide, Access Reviews Guide.