MemberOf retirement in Entra ID: two announcements, one design question

Table of contents
- What Microsoft actually announced
- Timeline
- Gate 1 – Do you have Entra ID Governance?
- Gate 2 – Why do you have groups in groups?
- A pragmatic migration plan
- Testing the migration in a lab tenant
- Pitfalls
- Strategic perspective – what this really changes
- Wrapping up
What Microsoft actually announced
Microsoft published two Message Center posts about the memberOf rule operator for dynamic membership in Microsoft Entra ID. At first glance they look contradictory.
- MC1448379 (August 5, 2026): the public preview of the
memberOfoperator ends and the operator is retired on November 3, 2026. This affects dynamic membership groups, dynamic administrative units and entitlement management auto-assignment policies that use it. - MC1488839 (October 6, 2026): for organizations with Microsoft Entra ID Governance, support for existing
memberOfconfigurations is extended through March 31, 2027. A replacement capability on a new architecture is targeted for late 2026, and Microsoft will automatically migrate configurations that still usememberOfby the deadline. - https://learn.microsoft.com/en-us/entra/identity/users/groups-dynamic-rule-member-of
The second post describes itself as a targeted migration extension, not a change to the retirement announced for other customers. Same feature, two timelines – and the dividing line is a license.
This post is based on a lab test, not on a customer rollout. I will say so where it matters.
Timeline
The visualization below illustrates the timeline of the two announcements.
In other words: without Entra ID Governance, November 3 is your date. With Governance, you have until March 31, 2027 – but the question behind the rules does not go away.
Gate 1 – Do you have Entra ID Governance?
“Can we wait for the replacement capability – or do we have to rebuild before November 3?”
If you have Governance:
- Your existing configurations keep working through March 31, 2027.
- When the replacement launches, you can migrate yourself, ask Microsoft to migrate for you, or do nothing and let the automatic migration run.
- Use the time to inventory your groups anyway. An automatic migration moves your design, it does not improve it.
If you do not have Governance:
- Treat November 3 as a hard date. Rules with
memberOfstop being processed, so memberships stay in their last known state. - Everything that depends on those groups – licensing, Conditional Access targeting, app assignment – then works with outdated membership. Nothing throws an error, it just drifts.
- Your options are rewriting the rule with supported operators or properties, switching to assigned membership, or licensing Governance.
Ask yourself honestly whether you would buy Governance for this one feature. If Access Packages, Access Reviews and Lifecycle Workflows are not in use, the answer is probably no. That is the group this post is written for.
This is not an argument against Governance. Entra ID Governance is a sensible license when you want access to follow a process – requests, approvals, expiry, reviews and joiner/mover/leaver workflows – rather than the shape of your group hierarchy. If that describes your pain, the memberOf retirement is a good moment to evaluate it properly. If it does not, the attribute-based approach below gets you a clean result without it.
Gate 2 – Why do you have groups in groups?
“What problem does the nesting actually solve – and does it need to exist at all?”
Before touching a rule, I look at why the nesting was built. There are usually three reasons:
- Aggregation. A group like
Global-M365E5collectsCompany1-…,Company2-…andConsultants-…. For licensing, this is often unnecessary: a user can receive the same license through several groups and still consumes only one license. You can assign the license directly to each source group and drop the aggregator. - Missing identity data. The nesting exists because nobody maintains
department,companyNameor another attribute on the user. The group is a workaround for data that nobody owns. - A real process. Approvals, expiry, access reviews. This is what Entitlement Management and Governance are built for, and the one case where the license makes sense.
Reasons 1 and 2 are the majority in my experience. Reason 1 removes a group, reason 2 is where attributes on the user come in.
A related point on licensing: group-based licensing does not process nested groups (Microsoft documentation). A dynamic group with a memberOf rule is a flat group with user members, so it works – but it is easy to build a design that quietly breaks once someone converts it to assigned membership and adds groups as members.
A pragmatic migration plan
Phase 1 – Inventory
Find all dynamic groups whose rule contains memberOf. A starting point with Microsoft Graph PowerShell:
| |
This covers dynamic groups only. Dynamic administrative units and entitlement management auto-assignment policies need their own check.
Phase 2 – Decide per group
For every group from the inventory, pick one outcome:
- Aggregation: remove the aggregator and assign the license to the source groups.
- Missing attribute: model it as an attribute on the user (next phases).
- Real process: plan Governance, or accept manual assignment.
Phase 3 – Define a profile catalog
For licensing I use one attribute and a catalog of profile values. A profile describes a type of user, and each profile is mapped to a set of licenses by a dynamic group. The attribute can be any string attribute you control – standard attributes such as department or companyName are the best choice if HR maintains them. extensionAttribute1–15 work for both hybrid and cloud-only users and are what I use below.
🪪 Profiles describe the user, not the product
The most important design decision is what you write into the attribute. My first idea was the license itself, for example M365E5. That couples your user data to your product catalog: the day E5 is replaced by something else, you have to rewrite the attribute for every user.
Name profiles after who the user is and let the group decide what the user gets:
Value in extensionAttribute5 | Meaning | The group assigns |
|---|---|---|
KNOWLEDGE | Standard knowledge worker | Microsoft 365 E5 |
KNOWLEDGE+PM | Knowledge worker with project management | Microsoft 365 E5 and Project |
FRONTLINE | Frontline worker | Microsoft 365 F1 |
FRONTLINE+SEC | Frontline worker with additional security | Microsoft 365 F1 and the Defender add-on |
Each profile gets one dynamic group with an exact rule, and that group carries all the SKUs of the profile. A group can hold several licenses, so “frontline worker with additional security” is one group with two SKUs and this rule:
| |
If your top-tier plan is replaced by a new one, you swap the SKU on the group KNOWLEDGE. No user attribute changes. For a pilot, add a profile such as KNOWLEDGE-PILOT and move selected users into it.
A small convention helps: the part before the + is the persona, the parts after it are add-ons. Keep the values upper case and treat them as an allowlist – the backfill script in this post rejects everything that is not in the catalog.
Why profile values are the practical answer
- Readable and auditable.
KNOWLEDGE+PMexplains itself in the attribute, in the group name and in an access review. A coded value would need a separate legend. - Exact rules are performant.
-eqis the most efficient comparison, and-containsand-matchare less performant. - Multi-valued extension properties are not supported in dynamic rules. Single-valued strings are, which is why one profile string per user is the pattern that works.
- Custom security attributes cannot be used in dynamic group rules. They are built for attribute-based access control, not for group membership.
- Licenses can change without touching users. The profile stays, the SKUs behind it can be swapped.
What happens when the catalog grows?
Profile values scale with the number of combinations, not with the number of licenses. With 5 base profiles and 2 independent add-ons you can end up with up to 20 profiles, with 3 add-ons up to 40. In practice you only need the combinations that really exist – but keep an eye on this number, because every profile is a dynamic group you have to maintain.
Two things keep it manageable:
- Name profiles after the persona, not the product. A change of the underlying license is then a change on one group.
- Know your exit. If the matrix gets out of hand, split base profile and add-ons into two attributes, or move add-ons to a request-based process.
I tested this model in a lab with two profiles. I have no data on how it behaves with dozens of profiles in a large tenant.
Phase 4 – Backfill the attribute
The backfill reads the transitive members of each source group and writes the profile into the attribute. It follows a few rules that matter more than the script itself:
- Allowlist: only profiles from the catalog are accepted. A typo such as
Knowledge+pmwould otherwise leave users without a license. - Conflicts are not guessed: if a user ends up with two different profiles from two source groups, the script reports a conflict and sets nothing. This is a business decision.
- Existing values are not overwritten.
- Everything is exported to CSV as a base for review and rollback.
-WhatIffirst.
The script is in the next section.
Phase 5 – Ownership
A migration script is a one-off. The attribute lives on. Decide who maintains it – HR provisioning, the identity team or the on-premises AD team – and who is allowed to write it. Without an owner, you have moved the problem from group membership to attribute drift.
Testing the migration in a lab tenant
I tested the whole flow in a lab tenant with three test users before thinking about production. The scripts are numbered in the order they run. They need the Microsoft Graph PowerShell modules Microsoft.Graph.Users and Microsoft.Graph.Groups.
The test users cover the three paths that matter:
lab.user1is in the Company1 source group and should getKNOWLEDGE.lab.user2is in the Consultants source group and should getKNOWLEDGE+PM.lab.user3is in both and creates a real conflict.
Click to expand: Procedures in a lab environment
1_setup.ps1 – create the lab
The script creates the users, three assigned source groups, a legacy aggregator group with a memberOf rule, one dynamic group per profile, and the two CSV files the backfill needs. Run it only in a test tenant. The legacy group can only be created while memberOf is still available.
| |
In a real tenant, the license assignment on the target groups would be the last step. I deliberately left it out of the lab so that no licenses are consumed.
2_backfill.ps1 – set the attribute
This is the actual migration script for cloud-only users. Run it with -WhatIf first, then without.
| |
The status values are:
| Status | Meaning |
|---|---|
Set | Attribute was written |
AlreadySet | Attribute already had the target value |
Conflict | User is in source groups with different profiles – nothing written, decide manually |
ResolvedConflict | Conflict case, but the attribute already contains one of the candidate profiles (decided manually) |
SkippedExisting | Attribute has a different value, not overwritten |
SkippedHybrid | Synchronized user, see the hybrid note in the pitfalls |
WhatIf | Dry run |
3_verify.ps1 – compare attribute and group membership
Dynamic groups need a few minutes to process. Run the verification afterwards with the CSV from the backfill. It compares who should be in each target group with who actually is.
| |
Unexpected is the interesting column. It lists users who are in a target group without coming from your backfill – for example because somebody wrote the attribute by other means.
4_cleanup.ps1 – remove the lab objects
The cleanup removes exactly the objects that the setup stored in the state file. Do not point it at a production tenant.
| |
Lab results
The outputs below come from my first lab run, in which I used the product-style values M365E5 and M365E5+PROJECT as profile values. The logic is identical with the persona values used in the scripts above.
The first real run of the backfill, after the dry run:
| |
lab.user1 and lab.user2 received their profiles, lab.user3 was reported as a conflict and left untouched. I then decided the conflict by hand and set the attribute for lab.user3 myself. After a second backfill run, the status for that user changed to ResolvedConflict, and the verification matched in both groups:
| |
This is a lab with three users, not a production rollout. It shows that the logic works, not how it behaves at scale.
Pitfalls
- Hybrid users: the script above skips synchronized users (
SkippedHybrid). For users that come from on-premises Active Directory, the attribute has to be written in AD and synchronized by Entra Connect. I did not cover this in the lab. In a hybrid environment, adapt the script so that it writes the value with the Active Directory module (for exampleSet-ADUser -Replace @{ extensionAttribute5 = '<profile>' }) and check that your sync configuration includes the extension attributes. - Who can write the attribute? A dynamic group is only as trustworthy as the permissions on the attribute in its rule. If users – or a broadly delegated group – can modify the attribute, they can influence licensing or access. Review the permissions in AD and in Entra and restrict write access to the owning process. This is a recommendation, not something I have tested in the lab.
- Typos and drift: a wrong value silently leaves a user unlicensed. Validate values against the catalog and run a verification regularly.
- Product names in attributes: writing
M365E5into a user attribute ties your user data to a product. Use persona-style profiles and swap the SKU on the group. - Custom security attributes cannot be used in dynamic group rules – they are meant for attribute-based access control.
Strategic perspective – what this really changes
Nested groups were never a design. They were a workaround for identity data that nobody owned. The memberOf operator made that workaround convenient, and the retirement makes its cost visible.
Moving the logic to attributes on the user is more than a migration fix. Access decisions become auditable – you can see why a user has a license – and they no longer depend on the topology of groups. Describing the user with a persona profile also decouples your identity data from your product catalog: the user stays a KNOWLEDGE worker, whichever license that persona gets next year. It also works without Entra ID Governance, which matters because many organizations will not buy it for this one feature.
If you do have Governance, the extension buys you time, but it does not answer Gate 2. An automatically migrated nested-group design is still a nested-group design.
Wrapping up
- The two announcements describe one retirement with two timelines, split by Entra ID Governance.
- Without Governance, plan for November 3. With Governance, you have until March 31, 2027 – but inventory your groups now.
- Ask why the nesting exists before you migrate it. For licensing, you can often drop the aggregator and assign the license to the source groups.
- Where identity data is missing, put it on the user as a profile attribute, name the profile after the persona and not the product, and name an owner for it.
The era of “just nest another group” is coming to an end. Treat it as a chance to clean up, not as a deadline to survive.