Build a Conditional Access baseline in report-only
Create three baseline policies in report-only mode with Graph PowerShell, measure what they would have done for two weeks, then switch them on with no surprises.
- time
- 1 hour, then 1 to 2 weeks of watching
- level
- Intermediate
- cost
- Entra ID P1. Log Analytics ingestion if you use the workbook.
- Conditional Access Administrator or Security Administrator
- Break-glass accounts to exclude (see the first lab)
- Sign-in logs sent to Log Analytics, for the workbook and the query in step 5
- Microsoft Graph PowerShell installed
- 01
Connect and collect the exclusions
Every policy in this lab excludes your break-glass accounts. Put them in a group if you haven't already, so new policies only need one exclusion.
Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess","Policy.Read.All","Group.Read.All" $bg = (Get-MgGroup -Filter "displayName eq 'CA-Exclude-BreakGlass'").Id - 02
Block legacy authentication
Legacy protocols such as basic-auth IMAP and POP can't do MFA, so they're a common way round it. The client app types
exchangeActiveSyncandothercover them. The stateenabledForReportingButNotEnforcedis report-only.$p = @{ displayName = "CA001 Block legacy authentication" state = "enabledForReportingButNotEnforced" conditions = @{ users = @{ includeUsers = @("All"); excludeGroups = @($bg) } applications = @{ includeApplications = @("All") } clientAppTypes = @("exchangeActiveSync", "other") } grantControls = @{ operator = "OR"; builtInControls = @("block") } } New-MgIdentityConditionalAccessPolicy -BodyParameter $p - 03
Require MFA for all users
$p = @{ displayName = "CA002 Require MFA for all users" state = "enabledForReportingButNotEnforced" conditions = @{ users = @{ includeUsers = @("All"); excludeGroups = @($bg) } applications = @{ includeApplications = @("All") } clientAppTypes = @("all") } grantControls = @{ operator = "OR"; builtInControls = @("mfa") } } New-MgIdentityConditionalAccessPolicy -BodyParameter $pIf you use workload identities or service accounts that sign in as users, list them now. They'll show up in the report-only results in step 5, and you can decide whether to exclude them or move them to managed identities.
- 04
Require phishing-resistant MFA for admins
This policy targets directory roles and uses the built-in authentication strength. Its ID,
00000000-0000-0000-0000-000000000004, is the same in every tenant. The role IDs below are Global Administrator, Privileged Role Administrator, Security Administrator and Conditional Access Administrator; add any others you use.$roles = @("62e90394-69f5-4237-9190-012177145e10", "e8611ab8-c189-46e8-94e1-60213ab1f814", "194ae4cb-b126-40b2-bd5b-6091b380977d", "b1be1c3e-b65d-4f19-8427-f6fa0d97feb9") $p = @{ displayName = "CA003 Phishing-resistant MFA for admins" state = "enabledForReportingButNotEnforced" conditions = @{ users = @{ includeRoles = $roles; excludeGroups = @($bg) } applications = @{ includeApplications = @("All") } clientAppTypes = @("all") } grantControls = @{ operator = "OR"; authenticationStrength = @{ id = "00000000-0000-0000-0000-000000000004" } } } New-MgIdentityConditionalAccessPolicy -BodyParameter $p - 05
Measure for one to two weeks
Report-only policies are evaluated at every sign-in and the result is logged, but nothing is enforced. Open any sign-in in the Entra admin center and look at the Report-only tab, or use the Conditional Access insights and reporting workbook. To see everything at once, run this in Log Analytics:
SigninLogs | where TimeGenerated > ago(14d) | mv-expand ca = ConditionalAccessPolicies | where tostring(ca.displayName) startswith "CA00" | summarize Signins = count(), Users = dcount(UserPrincipalName) by Policy = tostring(ca.displayName), Result = tostring(ca.result) | order by Policy asc, Signins descreportOnlyFailuremeans the policy would have blocked that sign-in.reportOnlyInterruptedmeans the user would have been asked for MFA they didn't do. Those two are what to investigate. - 06
Fix what would break
For each user or app in the failure results, decide: register MFA (send them a Temporary Access Pass or the registration link), move an app off legacy authentication, or add a documented, time-limited exclusion. Use the What If tool to check a specific user before switching on.
- 07
Switch on, one policy at a time
Start with the legacy authentication block, which usually has the smallest impact, and leave a few days between each policy. Tell the service desk first.
$id = (Get-MgIdentityConditionalAccessPolicy -Filter "displayName eq 'CA001 Block legacy authentication'").Id Update-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $id -State "enabled"Keep the report-only query saved. It's also the quickest way to test any policy you add later.