Group nesting is how permissions quietly become impossible to reason about. Nobody sets out to build a structure where a contractor ends up with finance access. It happens one reasonable-looking membership at a time, over years.
The fix is a convention applied consistently, plus a way to see what you’ve actually got.
Quick Facts
- AGDLP is the convention worth following: Accounts into Global groups, Global into Domain Local, permissions on Domain Local.
- Keep nesting to two or three levels. Beyond that nobody can answer “why does this person have access?”
- Circular nesting is possible and breaks token calculation in confusing ways.
- Kerberos tokens have a size limit. Users in hundreds of groups get authentication failures.
- Name groups so the purpose is obvious without opening them.
AGDLP, briefly
The convention that stops this getting out of hand:
| Step | What goes where |
| Accounts | User accounts… |
| Global groups | …go into global groups representing roles, e.g. GG-Finance-Staff |
| Domain Local groups | …which go into domain local groups representing resources, e.g. DL-FinanceShare-Modify |
| Permissions | …and permissions are assigned only to the domain local group |
The value is that roles and resources stay separate. Someone changing department moves between global groups; a share changing its permission model changes domain local groups. Neither requires touching the other, and neither requires editing an ACL.
The failure mode people fall into is assigning permissions directly to global groups, or worse to individual users. It works immediately and becomes unmaintainable within a year.
Finding what you’ve actually got
# Everything a user is in, including nested
function Get-NestedGroups {
param([string]$SamAccountName)
$user = Get-ADUser $SamAccountName -Properties MemberOf
$all = @{}
function Walk($groups, $depth) {
foreach ($g in $groups) {
$grp = Get-ADGroup $g -Properties MemberOf
if (-not $all.ContainsKey($grp.Name)) {
$all[$grp.Name] = $depth
Walk $grp.MemberOf ($depth + 1)
}
}
}
Walk $user.MemberOf 1
$all.GetEnumerator() | Sort-Object Value, Name |
Select-Object @{N='Group';E={$_.Key}}, @{N='Depth';E={$_.Value}}
}
Get-NestedGroups -SamAccountName jsmith
Run that against a long-serving employee and the result is usually surprising. Depth values above three are where auditing stops being practical.
Circular nesting
Group A contains Group B, which contains Group A. Active Directory permits it, and it produces membership that’s technically resolvable but impossible to reason about.
# Look for groups that are members of groups they contain
Get-ADGroup -Filter * -Properties MemberOf, Members | ForEach-Object {
$g = $_
foreach ($m in $g.Members) {
if ($g.MemberOf -contains $m) {
[PSCustomObject]@{ Group = $g.Name; CircularWith = (Get-ADObject $m).Name }
}
}
}
The token size problem
Every group membership adds to the Kerberos token. Users in a very large number of groups. Typically beyond about 1,000 SIDs, though the practical limit is lower. Start failing authentication in ways that look like anything but a group problem: HTTP 400 errors on internal sites, failed logons to specific applications, or connections that hang.
# Rough token size check
$user = Get-ADUser jsmith -Properties MemberOf, TokenGroups
"Direct groups : $($user.MemberOf.Count)"
"Total SIDs : $((Get-ADUser jsmith -Properties TokenGroups).TokenGroups.Count)"
If that total is in the hundreds, you have a structural problem rather than a per-user one, and it will get worse.
Keeping it manageable
Quick Steps
- Adopt AGDLP and stick to it. Consistency matters more than which convention you pick.
- Name groups so purpose is obvious. A prefix for type, then role or resource, then permission level.
- Cap nesting at three levels and treat exceptions as things to fix.
- Never assign permissions to individual users. It’s always faster now and always costs more later.
- Review quarterly. Empty groups, circular nesting, and groups nobody can explain.
- Document why each group exists, in the group’s own description field. It’s the one place that travels with it.
# Groups with no members - usually leftovers
Get-ADGroup -Filter * -Properties Members, Description |
Where-Object { $_.Members.Count -eq 0 } |
Select-Object Name, Description, DistinguishedName
Glossary
| Term | What it means |
| AGDLP | Accounts, Global, Domain Local, Permissions. The standard nesting convention. |
| Global group | Contains accounts from its own domain. Represents a role. |
| Domain local group | Can contain groups from any domain. Represents access to a resource. |
| Token bloat | Excessive group memberships causing authentication failures. |
| Circular nesting | Two groups each containing the other. |
| Effective permissions | The access someone actually has once all nesting is resolved. |
Frequently asked questions
How deep can group nesting go?
Technically very deep. Practically, three levels is where it stops being auditable. If you can’t explain someone’s access in one sentence, it’s too deep.
What’s the actual limit on group memberships?
There’s no hard cap, but Kerberos token size becomes a problem well before any theoretical limit, often around 1,000 SIDs, sometimes fewer depending on configuration.
Is AGDLP still relevant with cloud identity?
The principle is. Separating roles from resources. Entra ID uses different mechanics, but assigning access to roles rather than individuals is the same idea and just as important.
How do I find why someone has access to something?
Walk the nesting from the resource’s ACL back through the groups. The recursive function above does it from the user’s side; combine both to find the specific path.
Can I safely delete empty groups?
Usually, but check first. Some are placeholders for scheduled onboarding, and some are referenced by scripts or applications rather than by membership. Disable or rename before deleting if unsure.
Gear We Recommend
Testing AD structure changes safely needs a lab. Here’s ours.
Browse our Home Lab picks on AmazonAs an Amazon Associate, TechyGeeksHome earns from qualifying purchases
Disclosure: this post may contain affiliate links. If you buy through one of them, we may earn a small commission at no extra cost to you. We only recommend products we’ve tested or genuinely rate.
Discover more from TechyGeeksHome
Subscribe to get the latest posts sent to your email.