Nested Groups: Why Your SharePoint Permissions Report Is Wrong, and How to Expand Entra ID and AD Groups

Last updated: 2026-10-21

A SharePoint permissions report that lists "Marketing" as one row may be hiding hundreds of people. SharePoint stores the grant against the group, and Entra ID or Active Directory groups can contain other groups. To see the real list of people, the report has to read the directory and follow nested groups down to each user. SharePoint Essentials Toolkit does this, free on up to 20 sites.

A SharePoint permissions report that lists "Marketing" as one row may be hiding hundreds of people. SharePoint stores the grant against the group, and Entra ID or Active Directory groups can contain other groups. To see the real list of people, the report has to read the directory and follow nested groups down to each user. SharePoint Essentials Toolkit does this, free on up to 20 sites.

Why do nested groups matter?

An auditor asks who can open the Finance library. Your report says "Finance Readers" and "Everyone except external users". Both answers are technically correct and practically useless. The auditor wants names.

The risk is real too. A security group added to a site years ago may now contain contractors, a whole department, or another group someone added for convenience. Nobody looks inside, so nobody notices. Before a Microsoft 365 Copilot rollout this matters more, because every person in that chain can ask Copilot about the content.

What are the four kinds of group in SharePoint?

GroupWhere it livesCan it nest?
SharePoint group (Owners, Members, Visitors, custom)One site collectionCannot contain another SharePoint group, but can contain the three groups below
Microsoft 365 groupEntra ID; connected to a team site or TeamMembers are users (owners and members)
Entra ID security group (or AD group on-premises)DirectoryYes, can contain other security groups, many levels deep
Everyone / Everyone except external users / All authenticated usersBuilt-in claimsMeans "everyone" of that type; not a list you expand

Microsoft explains how sharing and group access fit together in Sharing and permissions in the SharePoint modern experience.

A worked example: one row, 400 people

Here is a typical chain (illustrative, but we see this shape in real tenants):

  1. The Marketing site's Members SharePoint group has Edit.
  2. Inside Members is the Entra ID security group SG-Marketing.
  3. SG-Marketing contains 60 people and two more groups: SG-Marketing-Agency (outside contractors) and SG-Sales-All.
  4. SG-Sales-All contains 340 people.

A report that stops at the SharePoint group shows "Members: Edit". A report that stops at the first directory group shows "SG-Marketing". Only a fully expanded report shows that 400 people, including agency contractors and the whole sales team, can edit marketing files.

Option 1: SharePoint and the Microsoft 365 admin centers

You can follow a chain by hand. It takes three places:

  1. The site. Select Settings > Site permissions > Advanced permissions settings. Note each SharePoint group and any directory group granted access directly. Select a SharePoint group to see its members; directory groups inside it appear as single entries.
  2. Microsoft Entra admin center. In the Entra admin center, go to Groups > All groups, open each directory group from step 1 and select Members. Nested groups appear as entries you open in turn, one level at a time.
  3. Microsoft 365 admin center. For a group-connected team site, open Teams & groups > Active teams & groups, select the group and view Membership for its owners and members.

To test one person instead, use Check Permissions on the site's Advanced permissions page. It reports whether they have access and through which group.

All of this is accurate and included in your license. It works forward from a group or backward from a person, one level and one site at a time, and nothing joins the pieces into a single list of names.

Option 2: PowerShell with PnP and Microsoft Graph

Microsoft Graph's Get-MgGroupTransitiveMember follows nesting for you. The work is connecting it to SharePoint. SharePoint stores directory groups as claim login names that contain the Entra object ID:

  • Security group: c:0t.c|tenant|<object-id>
  • Microsoft 365 group members: c:0o.c|federateddirectoryclaimprovider|<object-id>
  • Microsoft 365 group owners: the same, ending in _o

The script below reads one site's direct grants and SharePoint group members, finds the directory groups among them, and expands each to its people. Install PnP PowerShell 2.x or later and Microsoft Graph PowerShell, and register your own Entra ID app for PnP.

# Expand directory groups on one site to the people inside them
$ClientId = "<your-app-id>"
$SiteUrl  = "https://contoso.sharepoint.com/sites/Marketing"
Connect-PnPOnline -Url $SiteUrl -Interactive -ClientId $ClientId
Connect-MgGraph -Scopes "GroupMember.Read.All", "User.Read.All"

function Get-EntraGroupId($login) {
    if ($login -match '^c:0t\.c\|tenant\|([0-9a-f-]{36})
    
    
    
    
    
  

) { return $Matches[1] }
    if ($login -match '^c:0o\.c\|federateddirectoryclaimprovider\|([0-9a-f-]{36})(_o)?
    
    
    
    
    
  

) { return $Matches[1] }
}

$principals = @()
$web = Get-PnPWeb
Get-PnPProperty -ClientObject $web -Property RoleAssignments | Out-Null
foreach ($ra in $web.RoleAssignments) {
    Get-PnPProperty -ClientObject $ra -Property Member | Out-Null
    $principals += [pscustomobject]@{ Via = "Direct"; Login = $ra.Member.LoginName; Name = $ra.Member.Title }
}
foreach ($group in Get-PnPGroup) {
    Get-PnPGroupMember -Group $group | ForEach-Object {
        $principals += [pscustomobject]@{ Via = $group.Title; Login = $_.LoginName; Name = $_.Title }
    }
}

$rows = foreach ($p in $principals) {
    $id = Get-EntraGroupId $p.Login
    if (-not $id) { continue }   # a person, a SharePoint group or an Everyone claim
    $members = if ($p.Login -like "*_o") { Get-MgGroupOwner -GroupId $id -All }
               else { Get-MgGroupTransitiveMember -GroupId $id -All }
    $members | Where-Object { $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.user' } |
        ForEach-Object {
            [pscustomobject]@{
                SharePointGroup = $p.Via
                DirectoryGroup  = $p.Name
                User            = $_.AdditionalProperties.userPrincipalName
            }
        }
}

$rows | Export-Csv "C:\Reports\expanded-groups.csv" -NoTypeInformation -Encoding UTF8

What to know:

  • It covers site-level access only. Lists, folders and files with unique permissions need the loops from the SharePoint permissions report article.
  • It lists every SharePoint group on the site, including any that have no permissions. Compare it with the site's grants before reporting.
  • Large groups expand to many rows. Graph can return thousands of members for one group, so set a size limit for production use.
  • On-premises, use Get-ADGroupMember -Recursive from the ActiveDirectory module instead of Graph.

Option 3: Expand groups in the SharePoint Essentials Toolkit permissions report

The SharePoint permissions report has a setting called Include Domain Group Members. Turn it on and the report lists the people inside Entra ID, Microsoft 365 and Active Directory groups, following nested groups. The Granted Through and Granted Through Path columns show which group gave each person access.

1. Turn on Include Domain Group Members

Start a permissions report, pick your sites, and open Settings. Turn on Include Domain Group Members. SharePoint group members are always included; this setting adds directory groups.

Include Domain Group Members setting to expand nested groups in a SharePoint permissions report
The Settings tab. Include Domain Group Members expands directory groups to their members.

2. Make sure the connection can read the directory

For SharePoint Online, expanding groups reads Entra ID through Microsoft Graph, so the connection needs an Azure app registration. If it does not have one, the app turns the option off and shows a link to the setup steps. On-premises sites (2016/2019) read Active Directory directly and need nothing extra.

Some quick reports, such as stale content open to everyone, check only direct grants to Everyone claims and links. They tell you so before you run them, and point you to the full report with group expansion:

Warning that groups are not looked inside for a SharePoint report, with the option to set up Azure app registration
The app says when a report does not look inside groups, and how to get that view.

3. Run and read the expanded report

Run the report. It adds a row for each person found inside each group. The Total Members Count column shows how many people sit behind each SharePoint or domain group, counting nested members. Sort by it to find the groups that open content to the most people.

4. Cross-check with the user inventory

The Users and groups on each site report (an inventory, not a permissions report) lists every user and domain group known to each site, including guests with the #ext# login form. It is a fast way to spot which directory groups have been added to a site at all.

SharePoint users and domain groups inventory by site, including guest accounts
Users and domain groups per site, with login names and account types.

What about Everyone, Everyone except external users and very large groups?

  • Everyone claims are never expanded. "Everyone except external users" means every internal account. The report shows it as one row and marks it as open to everyone. That is the right signal: treat it as company-wide access. The report on Copilot oversharing starts there.
  • Very large groups are listed but not expanded. By default any domain group with more than 2,000 members is skipped for expansion so it does not dominate the report. You can change the threshold, and you can list groups to never expand.
  • Dynamic groups are read like any other Entra group: the report shows the members at the time it runs. Membership can change tomorrow, so keep the export date with the evidence.

What to do with the findings

  • Replace broad security groups on sensitive libraries with a smaller, named group.
  • Remove groups nested "for convenience" inside other groups, especially ones that contain contractors.
  • Replace Everyone except external users with the group that actually needs access.
  • For a single person, run everything one person can access to see every route they have.

Most of these fixes happen in Entra ID or in SharePoint group membership. Where the fix is in SharePoint permissions, the report's Actions panel can apply it after you review each change. Community Edition can apply small fixes; bulk changes need a paid edition.

Frequently asked questions

Can a SharePoint group contain another SharePoint group?

No. SharePoint groups cannot contain other SharePoint groups. They can contain users, Entra ID security groups, Microsoft 365 groups and, on-premises, Active Directory groups. Those directory groups can contain further groups, which is where nesting happens. A report has to read the directory, not just SharePoint, to list the people at the bottom of the chain.

Why does my permissions report show a group name instead of people?

SharePoint stores the grant against the group, not against each person. Most tools and scripts read SharePoint only, so they stop at the group name. To list the people, the report must read group membership from Entra ID through Microsoft Graph, or from Active Directory on-premises, and follow nested groups down to individual users.

Is Everyone except external users expanded?

No, and it should not be. Everyone except external users means every internal account in the tenant, so listing its members would repeat your whole directory. The report shows it as one row and flags it as open to everyone. Treat any grant to it as company-wide access and decide whether that content should be narrowed to a named group.

What do I need to expand Entra ID groups in SharePoint Essentials Toolkit?

For SharePoint Online, the connection must use an Azure app registration so the toolkit can read group membership through Microsoft Graph. The app lets you set this up on the connection. On-premises sites read Active Directory directly and need no extra setup. Without the app registration, the report still runs and shows each group as one row.

Are very large groups expanded?

By default, any domain group with more than 2,000 members is listed but not expanded, so one huge group does not swamp the report. You can change the threshold in Settings, and you can name groups whose membership you never want expanded. The group still appears with its permission level, so the grant is never hidden.

Run the permissions report with group expansion, free

SharePoint Essentials Toolkit Community Edition is free. Expand nested groups in a full permissions report on up to 20 sites per Microsoft 365 tenant, with no item caps and no trial period. Get your free Community Edition license key.