Skip to main content
Microsoft Entra ID · PowerShell 7.6

Who holds each Entra ID directory role

Who is a member of each activated Microsoft Entra directory role (Global Administrator, Exchange Administrator and so on)?

Script

#Requires -Modules Microsoft.Graph.Authentication, Microsoft.Graph.Identity.DirectoryManagement
# Members of every activated Entra ID directory role. Read-only (GET requests only).

Connect-MgGraph -Scopes 'Directory.Read.All' -NoWelcome

$roles = Get-MgDirectoryRole -All | Sort-Object DisplayName
foreach ($role in $roles) {
    $uri = '/v1.0/directoryRoles/' + $role.Id + '/members?$select=id,displayName,userPrincipalName'
    while ($uri) {
        $page = Invoke-MgGraphRequest -Method GET -Uri $uri
        foreach ($member in $page['value']) {
            [pscustomobject]@{
                Role              = $role.DisplayName
                MemberType        = $member['@odata.type']
                DisplayName       = $member['displayName']
                UserPrincipalName = $member['userPrincipalName']
                MemberId          = $member['id']
            }
        }
        $uri = $page['@odata.nextLink']
    }
}

Checked automatically against Microsoft's published cmdlet reference. KBY hasn't run it in your tenant; run it in a test environment first.

Reading the output

  • Requests Directory.Read.All rather than only RoleManagement.Read.Directory: the members API returns only id and @odata.type for member types the caller cannot read, so names would be blank.
  • Lists members of activated directory roles as returned by the directoryRole members API. Microsoft now recommends the unified RBAC API for new work; this report uses the long-standing directoryRole API because its output is the simplest to read.
  • Members can be users, groups or service principals; MemberType shows which.

Sources

The Microsoft reference page for every cmdlet the script calls, plus the API and product pages behind each permission and caveat.

All scripts