top of page

Conditional Access Policy Plans in Preview: What I Found Testing Them Against Live Policies

Writer: Derek Morgan
Derek Morgan
24 minutes ago
8 min read

The Conditional Access baseline I maintain has 28 policy templates. Between them, they reference exclusion groups 55 times. The list of 39 admin roles is written out in full twice.


That duplication has a cost. Changing the 3 exclusion groups that 14 policies share means editing all 14, one at a time, and hoping none gets missed.


In October 2026, Microsoft put Conditional Access policy plans into preview. A plan holds shared conditions once, and the rules inside it inherit them. In my baseline, that would remove about half of the exclusion references.


I wanted to know how plans behave before recommending them, so I built 3 plans in a demo tenant. Every rule ran in report-only next to its enforced original policy, and I compared their decisions on real sign-ins.


How a plan works

A plan has details (name, owners, tags), optional shared conditions, and at least 1 rule. Each rule is evaluated as its own decision. Plans and standalone policies apply together, with no precedence: every policy and every rule that applies must be satisfied.


Microsoft's concept page sets a few constraints:

  • All users and All resources can only be set on a rule, never in shared conditions.

  • Shared conditions can't mix identity types, so users and agents need separate plans or rule-level targeting.

  • A rule can add its own exclusions. It can't remove an exclusion set at plan level.


Microsoft's plan pages point to the standard Conditional Access license requirement, Microsoft Entra ID P1. Creating or editing a plan needs the Conditional Access Administrator role.


The Learn plan pages don't mention the API. The Microsoft Graph beta reference documents it: plans at /identity/conditionalAccess/plans, rules under /plans/{id}/rules. That's a separate endpoint from /policies. My policy count stayed at 29 the whole time, even with 9 rules running. Any script, backup or report that reads only /policies doesn't see plans.


One preview caveat matters for design. Microsoft says plans that target users with a Location condition get 1-hour access tokens without the instant IP enforcement check during preview. Location policies should stay standalone until that's lifted.


Cloud Harbor Consulting graphic showing 3 standalone policies merging into 1 plan with inherited exclusions and rules.
Streamline policy management by setting exclusions just once, allowing all rules to inherit predefined conditions for efficient access control.

How I tested it

The demo tenant runs 29 enforced policies. I left all of them untouched and set every plan rule to report-only, so no experiment could change anyone's access.


I wrote 2 read-only PowerShell scripts for the comparison. The first exports every plan with its rules and compares each rule with the policy of the same name. The second reads sign-in logs and pairs each rule's decision with its policy's decision on the same sign-in. Both are in the M365-Security-Frameworks repository, with the three plans and a deployer that creates them with every rule in report-only.

Plan

Built with

Rules

What it tested

Admins

Migration wizard

2, targeting 39 admin roles

Identical targeting that isn't All users

Session hardening

Migration wizard

4, all targeting All users

What the wizard does with All users policies

Guests

Built from scratch

3, targeting all 6 guest types

Guest-type exclusions and Terms of Use on a rule

Policy evaluation held up. In the final test window, after the fix described in finding 7, 90 sign-ins across all 9 rules produced 0 decision differences between rules and their policies. The problems I found are in the tooling around plans.


Microsoft Entra ID plan page for CAB-P3-Global-SessionAndClientHardening, showing rules, excluded groups, and plan details.
Overview of the settings for "CAB-P3-Global-SessionAndClientHardening" in Microsoft Etra ID, detailing the plan's configurations, creation date, and ownership, along with shared conditions and specific rules concerning excluded groups and client app types.

What I found

1. The wizard left shared conditions empty

Microsoft's migration guide says "Settings that the selected policies have in common become shared conditions."


For the admin policies, that's what happened. The 39 roles and the 3 exclusion groups moved to the plan.


For the 4 session-hardening policies, the wizard created no shared conditions at all. All 4 policies exclude the same 3 groups, and the wizard kept a copy of all 3 on every rule. When I built the guest plan from scratch, the shared conditions were created at plan level, with no copies on the rules.


My read: All users can't be set at plan level, so the wizard keeps all identity targeting, exclusions included, in each rule. That's an inference. Microsoft doesn't document it.


2. Plan and rule conditions don't all combine the same way

Exclusions add up, as documented. A rule excluding the service provider guest type on top of a plan that includes all 6 guest types worked as intended, with the same effective scope as the original policy.


Client app types behave differently. When I edited the session-hardening plan, the portal added a shared client app type of "All". One rule was set to Browser. If those combined by adding up, that rule would also have applied to desktop and mobile apps.


It didn't. 26 desktop-app sign-ins showed the rule not applying, with client type as the unmet condition. Client app types must match both the plan and the rule, and "All" means no restriction. I haven't tested platforms or risk levels yet.


Cloud Harbor Consulting infographic titled How plan and rule conditions combine, with exclusions and client app types.
Cloud Harbor Consulting illustrates how plan and rule conditions combine, emphasizing exclusions and client app types. Exclusions can introduce additional rules without removing plan settings, shown with examples like emergency access and service accounts. Client app types require matching both plan and rule conditions, narrowing the scope with rules such as browser specifications.

3. Rules show up in sign-in logs with no plan reference

Each rule appears in a sign-in's applied Conditional Access policies as its own entry, with the rule's ID, the rule's name and the same fields as a policy. Nothing in the entry names the plan.


The wizard keeps each original policy's name on its rule. During a migration, a rule and its source policy carry the same name, and only the ID tells them apart. Any sign-in log query or report that filters by policy name will count both. Compliance reports built on policy names will double-count during a migration.


4. The portal shows a merged view that Graph doesn't store

In the rule editor, inherited items show a link icon, no remove button, and the tooltip "Inherited from plan." For wizard-created rules, Graph still stores each rule's own copy of those exclusions.


The read-only rule details panel had a different gap. For the device code flow rule, it listed the users, apps, client app types and the Block control, and left out the authentication flow condition entirely. Read on its own, the panel describes a rule that blocks everything. The editor showed the condition correctly. A change reviewer reading the details panel would approve the wrong scope.


Microsoft Entra admin center Edit Rule page showing a conditional access rule form, report-only state, included users, and Save button.
Editing a rule in the Microsoft Entra admin center, labeled "CA-COV004-Global-BlockDeviceCodeFlow." The rule is configured to be in report-only mode, targeting all users while excluding specific groups, and applying to all resources.
Microsoft Entra admin center showing CA-COV004-Global-BlockDeviceCodeFlow rule details, report-only, with block control and excluded groups.
Configuration overview of the "CA-COV004-Global-BlockDeviceCodeFlow" rule in Microsoft Entra admin center, currently set to "Report-only" for all users, with specific exclusions and a block control on all client app types.

5. What If evaluates rules, with 2 gaps

The What If tool lists rules as [Plan: name] [Rule: name] alongside policies, and the reason each rule didn't apply matched its policy's reason.


The first gap: one rule appeared in neither the "will apply" list nor the "will not apply" list, while its policy applied. It's the only rule with a device filter and the only one with session controls and no grant control. I haven't isolated which of those drops it.


The second gap: the user picker won't accept guests. It shows "Guest users are not allowed." So a guest plan can't be checked in What If at all.


A change process that relies on What If to approve plan edits will miss rules.


Microsoft Entra admin center What if page showing policy evaluation results and a list of applicable access policies.
Microsoft Entra admin center displaying a list of conditional access policies, including multifactor authentication requirements and access restrictions based on specific criteria.

6. The migration picker can create duplicates

The picker shows each policy's name and state. It doesn't mark policies already copied into a plan, so a policy already in a plan can be selected again, with no warning.


On one migration attempt, the audit log shows a plan named "Migrated policy plan" created and deleted 20 seconds apart. Name the plan before you finish the merge, and check the audit log afterward.


7. Report-only and enforced results need one translation

When a sign-in hits an MFA or Terms of Use prompt, the enforced policy logs failure and the report-only rule logs reportOnlyInterrupted. Both mean the user was stopped for the same control.


My first comparison flagged 7 differences. All 7 were this pair. Any script that compares report-only results with enforced results has to treat them as equal.


One more timing note: new and changed rules took 6 to 9 minutes to show up in sign-in evaluations. Test too early and you'll see notEnabled results that disappear later.


The business case

Moving the whole baseline to plans would take it from 28 objects to 14: 8 plans holding 22 rules, plus 6 standalone policies that don't fit a plan. Exclusion references would fall from 55 to 27. The 39-role admin list would exist once.


Cloud Harbor Consulting infographic on simplifying access policies, with three donut charts and headline Half the objects to maintain.
Efficiently reducing complexity, Cloud Harbor Consulting consolidates 28 Conditional Access policies into 8 streamlined plans, minimizing objects, exclusions, and admin role list copies while highlighting areas of potential risk and exclusion.

The mechanism is fewer edit points. Adding an exclusion becomes 1 plan edit, where today it can be 14 policy edits. Every edit skipped is one less chance for policies that should match to drift apart.


Plans remove duplication within a plan, not across plans. The emergency access exclusion still appears in 9 places, because each plan and each standalone policy needs it.


For a CISO, the risk is in plan-level exclusions. A plan-level exclusion applies to every rule in the plan. Put an exclusion there that only 1 of 4 member policies had, and the other 3 just covered fewer users without anyone editing them. The design rule I use: a plan's shared exclusions are only the ones every member policy already had.


Recovery is the other cost. If plans are deleted or the tenant is rebuilt, a policy-only backup restores none of the plan rules. If plans enforce controls, they need their own export, kept with their rules.


Moving production to plans now buys a smaller object count at the cost of a preview's support terms, the location token caveat and the tooling gaps above. Prototyping in report-only costs a few hours and changes no one's access.


How to evaluate plans in your tenant

  1. Build a prototype in report-only next to the original policies. Keep the originals enforced and unedited while you compare.

  2. For All users policies, build the plan from scratch; the wizard keeps their exclusions on every rule.

  3. Set plan-level exclusions to the intersection of the member policies' exclusions. Every other exclusion stays on its rule.

  4. Keep policies with Location conditions standalone during the preview.

  5. Name the plan before you finish a merge, and check the picker against plans you've already built.

  6. Wait about 10 minutes after any change before testing.

  7. Validate with sign-in logs, matching on rule IDs. Treat What If results as incomplete.

  8. Export plans with their rules, separately from your policy backups.

  9. Follow Microsoft's decommission order: turn the rules on, turn the originals off, and delete the originals only after a validation period.


My recommendation

Plans cut real duplication, and every rule I tested made the same decision as its policy. The tooling around them isn't ready for production: the wizard, What If, the rule details panel and backups all have gaps today.


For now, I'm keeping the baseline as standalone policies and leaving the 3 plans running in report-only. You can deploy the same plans to your tenant, report-only, and run the same comparison with the scripts in the repository.


One question Microsoft hasn't answered yet: whether plan rules count toward the tenant's Conditional Access policy limit. I'll update this post when that's documented.

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
bottom of page