In this module
MSA1.10 Group Architecture
You've created security groups to assign permissions and distribution lists to send email. You know from MSA1.6 that Administrative Units scope admin roles while groups scope resource access — they're complementary, not interchangeable. You know from MSA1.9 that consistent naming makes groups queryable. This sub teaches you to think about groups as an architectural layer — the mechanism that mediates between identities and everything they access. Every CA policy, every application assignment, every license allocation, every Teams channel, and every SharePoint site depends on groups. If the group architecture is wrong — wrong types, inconsistent membership models, no lifecycle management, no coordination with AUs or CA — then every downstream system inherits the structural weakness. Most tenants accumulate groups organically — the ratio of groups to users tells a story about growth without architectural design, and this sub reads it.
Groups are the connective tissue of M365 security. A CA policy targets a group. An application assignment references a group. A license allocation uses a group. A Teams channel is a group. A SharePoint site permission is a group. If the group architecture isn't designed deliberately — choosing the right type for each purpose, the right membership method, the right lifecycle, and the right coordination with AUs and CA policies — then every system that depends on groups inherits the structural problems. the tenant has 214 groups for 810 users. 31 are empty. 67 have no owner. 14 have a single member. The group landscape has grown organically for years with no design, no review, and no deletion. This sub teaches you to audit the current state, design the target architecture, and plan the migration.
Estimated time: 50 minutes.
The five group types — Graph API properties and architectural constraints
Every group in Entra ID is distinguished by a combination of three Graph API properties: groupTypes (an array — contains "Unified" for M365 groups, "DynamicMembership" for dynamic groups), securityEnabled (boolean — true for groups that can be used in access control), and mailEnabled (boolean — true for groups that can receive email). These three properties determine what the group can do, what it can contain, and how it's managed.
Connect-MgGraph -Scopes "Group.Read.All","GroupMember.Read.All"
$groups = Get-MgGroup -All -Property DisplayName, GroupTypes, SecurityEnabled,
MailEnabled, MembershipRule, MembershipRuleProcessingState,
IsAssignableToRole, CreatedDateTime, Description
# Classify every group using the Graph API property combination
$classified = $groups | ForEach-Object {
$g = $_
$type = if ("Unified" -in $g.GroupTypes -and "DynamicMembership" -in $g.GroupTypes) {
"Dynamic M365"
} elseif ("Unified" -in $g.GroupTypes) {
"M365"
} elseif ("DynamicMembership" -in $g.GroupTypes) {
"Dynamic Security"
} elseif ($g.SecurityEnabled -and $g.MailEnabled) {
"Mail-Enabled Security"
} elseif ($g.SecurityEnabled -and -not $g.MailEnabled) {
"Security"
} elseif (-not $g.SecurityEnabled -and $g.MailEnabled) {
"Distribution List"
} else {
"Other"
}
[PSCustomObject]@{
Name = $g.DisplayName
Type = $type
GroupTypes = ($g.GroupTypes -join ", ")
Security = $g.SecurityEnabled
Mail = $g.MailEnabled
Dynamic = [bool]("DynamicMembership" -in $g.GroupTypes)
Rule = $g.MembershipRule
RoleAssignable = $g.IsAssignableToRole
}
}
$classified | Group-Object Type |
Select-Object @{N='Type';E={$_.Name}},
Count,
@{N='Pct';E={[math]::Round($_.Count/$groups.Count*100,1)}} |
Sort-Object Count -Descending | Format-Table -AutoSizeType Count Pct
---- ----- ---
Security 118 55.1
M365 48 22.4
Distribution List 24 11.2
Dynamic Security 12 5.6
Mail-Enabled Security 8 3.7
Dynamic M365 4 1.9Each type has specific architectural constraints that determine when to use it and when to avoid it:
Security groups (118, 55%) — securityEnabled: true, mailEnabled: false, no "Unified" in groupTypes. These are the access-control workhorses. They can contain users, devices, other security groups (nesting), and service principals. They're used for CA policy targeting, application RBAC assignments, SharePoint site permissions, and license allocation. They cannot receive email, cannot create a Teams channel, and cannot provision a SharePoint site. Nesting is supported — a security group can contain other security groups, enabling hierarchical access models (SG-All-Staff contains SG-Engineering-All, which contains SG-Engineering-Manchester).
M365 groups (48, 22%) — securityEnabled: true, mailEnabled: true, "Unified" in groupTypes. Creating an M365 group automatically provisions a shared mailbox, calendar, SharePoint site, and optionally a Teams channel. They can contain only users (not devices, not groups, not service principals — no nesting). They're designed for collaboration: project teams, department spaces, community groups. They're the wrong choice for pure access control because they create collaboration resources (mailbox, SharePoint site) that may not be needed, and they can't nest.
Distribution lists (24, 11%) — securityEnabled: false, mailEnabled: true. Email-only groups. Cannot be used for CA policy targeting, application assignments, or any access control purpose. They exist solely to distribute email to a list of recipients. In modern M365, most distribution list functions are better served by M365 groups (which include email plus collaboration tools). Distribution lists persist from legacy Exchange migrations and should be gradually consolidated.
Dynamic security groups (12, 6%) — same as security groups but with "DynamicMembership" in groupTypes and a membershipRule that automatically populates membership based on user or device attributes. Dynamic groups require P1 licensing for each unique user. The membership evaluates continuously — when an attribute changes, group membership updates within minutes.
# Examine the organization's dynamic group rules
$dynamicGroups = $classified | Where-Object { $_.Dynamic -eq $true }
Write-Host "Dynamic groups: $($dynamicGroups.Count)"
Write-Host ""
$dynamicGroups | Select-Object Name, Type, Rule | Format-Table -AutoSizeDynamic groups: 16
Name Type Rule
---- ---- ----
DG-Engineering-All Dynamic Security (user.department -eq "Engineering")
DG-Finance-All Dynamic Security (user.department -eq "Finance")
DG-IT-All Dynamic Security (user.department -eq "IT")
DG-HR-All Dynamic Security (user.department -eq "HR")
DG-Manchester-Devices Dynamic Security (device.displayName -startsWith "MAN-")
DG-Newcastle-Devices Dynamic Security (device.displayName -startsWith "NCL-")
...The dynamic rules show two patterns: department-based user groups using user.department (dependent on the 84.8% attribute coverage from MSA1.6) and device groups using device.displayName (dependent on a device naming convention that embeds the site code). Both are only as reliable as the source attribute.
Entra Admin Center
View groups by type:
Identity → Groups → All groups
The Group type column shows Security, Microsoft 365, or Distribution. Click any group → Properties for membership type (Assigned/Dynamic) and role-assignability. For dynamic groups, click Dynamic membership rules to see and edit the rule syntax.
Create a new group:
Click New group → select Group type (Security or Microsoft 365) → set Membership type (Assigned, Dynamic User, or Dynamic Device) → for dynamic, enter the Dynamic query rule → optionally toggle Microsoft Entra roles can be assigned to the group → add owners and members (for assigned) → Create
Mail-enabled security groups (8, 4%) — securityEnabled: true, mailEnabled: true, no "Unified" in groupTypes. A hybrid type that provides both access control and email. Cannot be dynamic. Cannot contain devices. The architectural recommendation is to avoid this type — use a security group for access control and a separate distribution list or M365 group for email. Dual-purpose groups create governance ambiguity: is the membership driven by who needs access, or by who needs to receive email? The two populations may not overlap.
Role-assignable groups — any security group created with isAssignableToRole: true. This property is immutable (set at creation, can't be changed later). Role-assignable groups can be assigned Entra directory roles — instead of assigning "Exchange Administrator" to individual users, you assign it to the group and manage membership. PIM (MSA4) can make the role assignment eligible rather than active. Role-assignable groups must use assigned membership (no dynamic) and have restricted creation permissions (only Global Admin or Privileged Role Admin can create them).
$roleGroups = $groups | Where-Object { $_.IsAssignableToRole -eq $true }
Write-Host "Role-assignable groups: $($roleGroups.Count)"Role-assignable groups: 0the tenant has zero role-assignable groups. All Entra role assignments are direct (user → role). This means role governance can't be managed through group membership, can't be reviewed through group access reviews, and can't leverage PIM group activation. MSA4 designs the PIM architecture that creates these groups.
Group sprawl — the full diagnostic
# Complete sprawl analysis
$sprawl = foreach ($group in $groups) {
$members = (Get-MgGroupMember -GroupId $group.Id -All -ErrorAction SilentlyContinue)
$owners = (Get-MgGroupOwner -GroupId $group.Id -All -ErrorAction SilentlyContinue)
[PSCustomObject]@{
Name = $group.DisplayName
Members = $members.Count
Owners = $owners.Count
Type = ($classified | Where-Object { $_.Name -eq $group.DisplayName }).Type
Created = $group.CreatedDateTime
AgeDays = [int]((Get-Date).ToUniversalTime() - $group.CreatedDateTime).TotalDays
HasDesc = [bool]$group.Description
}
}
# Summary metrics
$empty = ($sprawl | Where-Object { $_.Members -eq 0 })
$single = ($sprawl | Where-Object { $_.Members -eq 1 })
$noOwner = ($sprawl | Where-Object { $_.Owners -eq 0 })
$noDesc = ($sprawl | Where-Object { -not $_.HasDesc })
$oldEmpty = ($empty | Where-Object { $_.AgeDays -gt 180 })
Write-Host "=== Group Sprawl Diagnostic ==="
Write-Host "Total groups: $($groups.Count)"
Write-Host "Empty (0 members): $($empty.Count) ($([math]::Round($empty.Count/$groups.Count*100))%)"
Write-Host "Single member: $($single.Count)"
Write-Host "No owner: $($noOwner.Count) ($([math]::Round($noOwner.Count/$groups.Count*100))%)"
Write-Host "No description: $($noDesc.Count) ($([math]::Round($noDesc.Count/$groups.Count*100))%)"
Write-Host "Empty + older than 180 days: $($oldEmpty.Count) (DELETE candidates)"
Write-Host ""
Write-Host "Oldest empty groups:"
$empty | Sort-Object AgeDays -Descending |
Select-Object Name, Type, @{N='Created';E={$_.Created.ToString("yyyy-MM-dd")}}, AgeDays -First 10 |
Format-Table -AutoSize=== Group Sprawl Diagnostic ===
Total groups: 214
Empty (0 members): 31 (14%)
Single member: 14
No owner: 67 (31%)
No description: 142 (66%)
Empty + older than 180 days: 28 (DELETE candidates)
Oldest empty groups:
Name Type Created AgeDays
---- ---- ------- -------
old contractors group Security 2022-03-14 1513
Tom's test group Security 2022-08-22 1352
Project Alpha M365 2023-01-11 1210
Backup Admins 2 Security 2023-04-18 1113
Migration temp group Security 2023-06-22 1048
Summer interns 2023 Security 2023-09-01 977
vendor access Security 2023-11-15 902
Event planning committee M365 2024-01-22 834
IT helpdesk temp Security 2024-03-08 789
contractor access 2024 Security 2024-05-14 722Every metric is an architectural indicator:
31 empty groups (14%) — groups that contain zero members but still exist in the directory. Each occupies space in every group selection dropdown, every group list view, and every governance report. "Old contractors group" has been empty for over 4 years. "Tom's test group" has been empty for nearly 4 years. These should be deleted — they serve no function and add noise to every group management operation.
67 ownerless groups (31%) — groups with no designated owner. When MSA12 designs access reviews, groups without owners can't be reviewed because there's nobody to confirm whether members still need access. The review system requires an owner or a designated reviewer. Assigning owners to these 67 groups is a prerequisite for governance.
142 groups with no description (66%) — two-thirds of groups have no description explaining their purpose. A group named "Manchester Office" with no description could be a site security group, a distribution list for office announcements, a SharePoint site group, or something Tom created for a project in 2023. Without a description, the purpose is unknowable without inspecting the membership and downstream references.
14 single-member groups — groups with exactly one member. Some may be legitimate (a CA exclusion group for one break-glass account). Most are likely mistakes — someone created a group intending to add more members and never did, or a group that previously had many members lost them all except one. Each should be reviewed: if the purpose is legitimate, document it. If not, delete the group and use a direct assignment instead.
Immediate cleanup actions
# DELETE: Empty groups older than 180 days
$toDelete = $empty | Where-Object { $_.AgeDays -gt 180 }
Write-Host "Groups to delete: $($toDelete.Count)"
Write-Host ""
foreach ($group in $toDelete) {
Write-Host "Deleting: $($group.Name) (empty for $($group.AgeDays) days)"
# Uncomment after review:
# Remove-MgGroup -GroupId (Get-MgGroup -Filter "displayName eq '$($group.Name)'").Id
}Before executing, verify that none of the empty groups are referenced by CA policies (even an empty group referenced by a CA policy is architecturally intentional — it may be a prepared exclusion group waiting for members). The verification query from MSA1.9's impact assessment covers this.
Coordinating groups with AUs and CA policies
The coordination between groups, AUs, and CA policies is the most architecturally important design decision in the group layer. MSA1.6 established that AUs scope admin roles and groups scope resource access. But CA policies target groups, not AUs. If you have a population (Manchester staff) that needs both admin delegation (AU) and CA policy targeting (group), the membership must match.
# Verify AU and group membership alignment for Manchester
# (This query works once the MSA1.6 AU design is implemented)
$auId = "ID-of-NE-Site-Manchester-AU"
$groupId = (Get-MgGroup -Filter "displayName eq 'SG-Manchester-Staff'").Id
$auMembers = (Get-MgDirectoryAdministrativeUnitMember -AdministrativeUnitId $auId -All).Id
$groupMembers = (Get-MgGroupMember -GroupId $groupId -All).Id
$inAUonly = $auMembers | Where-Object { $_ -notin $groupMembers }
$inGroupOnly = $groupMembers | Where-Object { $_ -notin $auMembers }
Write-Host "AU members: $($auMembers.Count)"
Write-Host "Group members: $($groupMembers.Count)"
Write-Host "In AU only: $($inAUonly.Count) (admin-scoped but NOT in CA policy)"
Write-Host "In group only: $($inGroupOnly.Count) (in CA policy but NOT admin-scoped)"If the numbers differ, the gap is a governance issue. Users in the AU but not the group are managed by the site admin but not targeted by site-specific CA policies. Users in the group but not the AU are targeted by CA policies but not manageable by the site admin. The coordination principle: if a population needs both AU scoping and CA targeting, use the same membership source for both. If the AU uses dynamic membership with a rule, create the group with the same dynamic rule.
Group-based licencing
Microsoft recommends group-based licensing over direct per-user license assignment. The architectural advantage: license allocation becomes an auditable, automatable group membership operation rather than a per-user administrative action that's invisible to governance queries.
# Check current license assignment method
$licenceGroups = Get-MgGroup -All -Property DisplayName, AssignedLicenses |
Where-Object { $_.AssignedLicenses.Count -gt 0 }
Write-Host "Groups with license assignments: $($licenceGroups.Count)"
if ($licenceGroups.Count -eq 0) {
Write-Host "No group-based licensing — all licenses assigned directly to users"
Write-Host "Recommendation: Create SG-Licence-E5 and SG-Licence-E3 groups"
Write-Host " and migrate from direct assignment to group-based"
}Groups with license assignments: 0
No group-based licensing — all licenses assigned directly to users
Recommendation: Create SG-Licence-E5 and SG-Licence-E3 groups
and migrate from direct assignment to group-basedNE assigns all licenses directly to users. The immediate improvement is creating SG-Licence-E5 (250 users — E5 users: IT, Security, Executives) and SG-Licence-E3 (600 users — everyone else), then migrating from direct assignment to group-based. MSA1.7's joiner workflow can then include "add to SG-Licence-E3" as a task — license assignment becomes part of the automated lifecycle.
Entra Admin Center
Configure group-based licensing:
Identity → Groups → select the license group → Licenses → Assignments
Click + Assignments → select the license (e.g., Microsoft 365 E5) → optionally toggle individual service plans on/off → Save
Monitor license assignment errors:
Identity → Groups → select the license group → Licenses → Processing status
Shows whether license assignment to all group members completed successfully. Common errors: insufficient licenses available, conflicting service plans, usage location not set on user.
the organization's target group architecture
Based on the sprawl analysis, the type classification, the naming convention from MSA1.9, and the coordination requirements with AUs and CA:
Category Convention Type Membership Count
-------------------- ---------------------------- ---------------- ---------- -----
Organization SG-All-Staff Security Assigned 1
Site (×6) SG-{Site}-Staff Security Assigned 6
Department (×10) DG-{Dept}-All Dynamic Security Dynamic 10
Licence SG-Licence-E5, SG-Licence-E3 Security Assigned 2
CA exclusion SG-CA-Exclude-BreakGlass Security Assigned 1
CA exclusion SG-CA-Exclude-LegacyApp Security Assigned 1
Application (×15) SG-App-{AppName} Security Assigned 15
Project (active ×8) M365-Project-{Name} M365 Assigned 8
Role (×6) SG-Role-{RoleName} Security* Assigned 6
Communication DL-{Scope} Distribution Assigned 12
Device site (×6) DG-{Site}-Devices Dynamic Security Dynamic 6
Target total: ~74*Role groups require isAssignableToRole: true at creation — cannot be converted from existing groups.
74 groups replaces 214 — a 65% reduction. The reduction sources:
- 28 empty groups deleted (zero members, older than 180 days)
- 14 single-member groups reviewed (most deleted, few legitimate ones documented)
- ~50 duplicate/overlapping groups consolidated (e.g., "finance team" and "Finance Users" and "DG-Finance-All" consolidated into one dynamic group)
- ~20 stale project/event groups deleted ("Summer interns 2023," "Project Alpha," "Event planning committee")
- ~30 ad-hoc/test/temp groups deleted ("Tom's test group," "Backup Admins 2," "IT helpdesk temp")
Groups created on demand, never reviewed, never deleted. Every project creates a new group. Every CA policy exception creates a new group. Every SharePoint site creates an M365 group. Every distribution list request from a department head creates a group. Nobody consolidates. Nobody assigns owners. Nobody deletes the empty ones. After 3 years, the tenant has more groups than users. The security architect can't design CA policies that target the right populations because the group landscape is incomprehensible — which of the 7 groups containing "Engineering" in the name is the one that should be targeted? The answer is: nobody knows, because the groups were created by 7 different people for 7 different reasons and none were documented. The architectural fix is intentional group design with defined types, defined purposes, defined ownership, and a defined lifecycle where groups that no longer serve a purpose are deleted.
Before moving on, verify your understanding: Run the group classification query against your tenant. Which type dominates? Explain why security groups are typically the majority and what architectural constraint M365 groups have that makes them unsuitable for pure access control. the tenant has 67 ownerless groups. Explain why this is a governance blocker, not just an administrative gap. What specific downstream process fails when a group has no owner?
Reusable script — the commands from this sub assembled for operational use:
Copy the sprawl diagnostic results, the type classification, and the target group architecture into your architecture package at 01-identity/group-architecture.md. Include:
- Current inventory by type (the classification output)
- Sprawl indicators (empty, single-member, ownerless, no-description counts)
- Immediate actions (delete empty >180d, assign owners, create license groups)
- Target group structure with naming convention applied
- Migration reference (MSA12 designs the consolidation timeline)
The group architecture is the foundation for MSA3 (CA policy targeting uses groups), MSA4 (PIM role-assignable groups), MSA5 (sensitivity label scope groups), MSA6 (device compliance groups), MSA7 (email security groups), and MSA12 (access review scope and group lifecycle management).
You're reading the free modules of m365-security-architecture
The full course continues with advanced topics, production detection rules, worked investigation scenarios, and deployable artifacts.