Skip to main content
Microsoft Entra ID · PowerShell 7.6

Delegated permission grants (user and admin consent)

Which apps can call which APIs on behalf of signed-in users, with which scopes, and was that consented for all users by an admin or by individual users?

Script

#Requires -Modules Microsoft.Graph.Authentication, Microsoft.Graph.Identity.SignIns, Microsoft.Graph.Applications, Microsoft.Graph.Users
# Delegated permission grants: which apps can act for users, on which APIs, with which scopes. Read-only.

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

$servicePrincipals = @{}
$users = @{}

function Get-CachedServicePrincipalName {
    param([string]$Id)
    if (-not $servicePrincipals.ContainsKey($Id)) {
        $servicePrincipals[$Id] = (Get-MgServicePrincipal -ServicePrincipalId $Id -Property 'displayName').DisplayName
    }
    return $servicePrincipals[$Id]
}

function Get-CachedUserPrincipalName {
    param([string]$Id)
    if (-not $users.ContainsKey($Id)) {
        $user = Get-MgUser -UserId $Id -Property 'userPrincipalName' -ErrorAction SilentlyContinue
        $users[$Id] = if ($user) { $user.UserPrincipalName } else { $Id }
    }
    return $users[$Id]
}

Get-MgOauth2PermissionGrant -All |
    ForEach-Object {
        [pscustomobject]@{
            Application = Get-CachedServicePrincipalName -Id $_.ClientId
            Api         = Get-CachedServicePrincipalName -Id $_.ResourceId
            ConsentType = $_.ConsentType
            User        = if ($_.ConsentType -eq 'Principal') { Get-CachedUserPrincipalName -Id $_.PrincipalId } else { 'All users' }
            Scopes      = "$($_.Scope)".Trim()
        }
    } |
    Sort-Object Application, Api, ConsentType, User

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

  • Directory.Read.All is the least privileged permission for listing oAuth2PermissionGrants. It also covers reading the service principal and user names the script looks up.
  • ConsentType AllPrincipals means an administrator consented for every user; Principal means one user consented for themselves, and User shows who.
  • Scopes is the space-separated scope string from the grant, for example "openid User.Read Mail.Read".
  • Makes one lookup per distinct app, API and user, cached, so large tenants with many user consents take a while.

Sources

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

All scripts