Getting all Azure AD consents using PowerShell

Customers should really start paying attention to their Azure AD application consents, which can be daunting. There are obviously tools for this, even provided by Microsoft through Cloud App Security (CAS), but you know – why not simply dump out everything in Excel and parse through it?

This blog post contains a simple PowerShell script that does exactly this.

Start by signing into the Graph Explorer as a global admin, and when you are there, copy the url. Then start the below PowerShell, which will monitor the clipboard in order to find a graph explorer url with an access token, and then use that to access the Microsoft Graph. Of course, you can do this different ways, but this is very handy for quick and dirty scripting.

function Get-AccessTokenFromGraphExplorerUrlOnClipboard
{
    [CmdletBinding()]
    [Alias()]
    Param
    ()

    Process
    {
        $first = $true
        do {
            if(!$first) {
                Sleep -Seconds 1   
            }
            $first = $false 

            Write-Verbose "Trying to get Graph Explorer URL from clipboard"
            $url = Get-Clipboard
            if($url -ne $null -and $url.StartsWith("https://developer.microsoft.com/en-us/graph/graph-explorer#access_token=")) {
                $token = $url -split "[=&]" | Select -Index 1
            }
        } while($token -eq $null -or !$token.StartsWith("ey"))
        $token
    }
}

$token = Get-AccessTokenFromGraphExplorerUrlOnClipboard -Verbose
$headers = @{Authorization = "Bearer $token"}
$VerbosePreference = "Continue"

# Get all Oauth2 permission grants from the tenant
$oauth2PermissionGrants = @()
$url = "https://graph.microsoft.com/beta/oauth2PermissionGrants?`$top=999"
do {
    $result = Invoke-RestMethod $url -Headers $headers -Verbose
    $oauth2PermissionGrants += $result.value
    $url = $result.'@odata.nextLink'
} while ($url)

$oauth2PermissionGrants | Out-GridView

# Fetch all related directory objects (applications, servicePrincipals, users etc)
$directoryObjects = @{}
$oauth2PermissionGrants | ForEach-Object {
    $oauth2PermissionGrant = $_ # $oauth2PermissionGrant = $oauth2PermissionGrants[0]
    
    if($oauth2PermissionGrant.clientId -and !$directoryObjects.ContainsKey($oauth2PermissionGrant.clientId)) {
        $directoryObjects[$oauth2PermissionGrant.clientId] = Invoke-RestMethod "https://graph.microsoft.com/beta/directoryObjects/$($oauth2PermissionGrant.clientId)" -Headers $headers
    }

    if($oauth2PermissionGrant.principalId -and !$directoryObjects.ContainsKey($oauth2PermissionGrant.principalId)) {
        $directoryObjects[$oauth2PermissionGrant.principalId] = Invoke-RestMethod "https://graph.microsoft.com/beta/directoryObjects/$($oauth2PermissionGrant.principalId)" -Headers $headers 
    }

    if($oauth2PermissionGrant.resourceId -and !$directoryObjects.ContainsKey($oauth2PermissionGrant.resourceId)) {
        $directoryObjects[$oauth2PermissionGrant.resourceId] = Invoke-RestMethod "https://graph.microsoft.com/beta/directoryObjects/$($oauth2PermissionGrant.resourceId)" -Headers $headers 
    }
}

$oauth2PermissionGrantsParsed = $oauth2PermissionGrants | ForEach-Object {
    $oauth2PermissionGrant = $_ # $oauth2PermissionGrant = $oauth2PermissionGrants[0]

    $obj = [ordered] @{
        clientId = $oauth2PermissionGrant.clientId
        clientDisplayName = $null
        clientType = $null
        consentType = $oauth2PermissionGrant.consentType
        expiryTime = $oauth2PermissionGrant.expiryTime
        startTime = $oauth2PermissionGrant.startTime
        resourceId = $oauth2PermissionGrant.resourceId
        resourceType = $null
        resourceDisplayName = $null
        principalId = $oauth2PermissionGrant.principalId
        principalDisplayName = $null
        principalType = $null
        scope = $oauth2PermissionGrant.scope
    }

    if($oauth2PermissionGrant.clientId) {
        $obj["clientDisplayName"] = $directoryObjects[$oauth2PermissionGrant.clientId].displayName
        $obj["clientType"] = $directoryObjects[$oauth2PermissionGrant.clientId].'@odata.type'
    }

    if($oauth2PermissionGrant.resourceId) {
        $obj["resourceDisplayName"] = $directoryObjects[$oauth2PermissionGrant.resourceId].displayName
        $obj["resourceType"] = $directoryObjects[$oauth2PermissionGrant.resourceId].'@odata.type'
    }

    if($oauth2PermissionGrant.principalId) {
        $obj["principalDisplayName"] = $directoryObjects[$oauth2PermissionGrant.principalId].displayName
        $obj["principalType"] = $directoryObjects[$oauth2PermissionGrant.principalId].'@odata.type'
    }

    [PSCustomObject] $obj
}

# Create a one row per scope version
$attributes = "clientId", "clientDisplayName", "clientType", "consentType", "expiryTime", "startTime", "resourceId", "resourceType", "resourceDisplayName", "principalId", "principalDisplayName", "principalType"
$oauth2PermissionGrantsParsedSingle = $oauth2PermissionGrantsParsed | ForEach-Object {
    $obj = $_
    $obj.scope -split " " | ForEach-Object {
        $obj2 = [ordered] @{scope = $_}
        $attributes | ForEach-Object {$obj2[$_] = $obj.$_}
        [PSCustomObject] $obj2
    }
}

# Output excel file
# If error on Export-Excel missing: Install-Module -Scope CurrentUser ImportExcel
$file = "~\Desktop\OAuth2 $([guid]::NewGuid()).xlsx"
$oauth2PermissionGrantsParsed | Export-Excel -Path $file -WorksheetName "Combined" -AutoSize -AutoFilter
$oauth2PermissionGrantsParsedSingle | Export-Excel -Path $file -WorksheetName "Single" -AutoSize -AutoFilter
ii $file 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s