List everyone who has an Application Role for applications in Azure

Some time ago I had to validate who or what has access to the applications we created in our Azure environment.
There were hundreds of different applications with each their own specific Application Roles. Both users and service principals had roles assigned to the applications to perform the required operations.

It is possible to click through every application in Entra ID and validate the assigned roles. However, this takes quite a bit of time.
So I figured “Is it possible to iterate through all my applications in Entra ID and see who or what has an application role assigned?”
Needless to say, the answer is “Yes!”.

By using the Azure CLI and the Graph API I was able to accomplish what is required.

#########################################################
# Login if running local and you haven't done so already
#########################################################
Function Login {
    # Subscription used for logging in. Necessary to get a context to work in.
    $loggedInSubscription = "The subscription name"
    $tenantId = "73fefcf4-c062-45ef-9607-e19aba33f82d"
    az login --tenant $tenantId
    # # Log in to a subscription which resides in the tentant we want to add & configure MG's to.
    az account set --subscription $loggedInSubscription
}
Function Get-AppRoleAssignments {
    [CmdletBinding()]Param()
    Write-Verbose -Message "Starting to retrieve all Enterprise Applications matching the naming convention."
    $roleAssignmentsForAllApplications = $null
    $enterpriseAppRegistrationCollection =
        az ad sp list --filter "startswith(displayname, 'jv-sample-app1') or startswith(displayname, 'jv-sample-app2')"
        | ConvertFrom-Json

    Write-Verbose -Message "Found $($enterpriseAppRegistrationCollection.Length) enterprise applications."
    foreach ($enterpriseAppRegistration in $enterpriseAppRegistrationCollection) {
        $servicePrincipalAppRoles = $null
        $assignedAppRolesForServicePrincipal = $null

        # The service principal from 'az ad sp list' already has all the data we need
        $servicePrincipalAppRoles = $enterpriseAppRegistration.appRoles

        Write-Verbose -Message "Found $($servicePrincipalAppRoles.Length) appRoles for $($enterpriseAppRegistration.id)."
        $assignedAppRolesForServicePrincipal =
            az rest `
            --method get `
            --uri https://graph.microsoft.com/v1.0/servicePrincipals/$($enterpriseAppRegistration.id)/appRoleAssignedTo
            | ConvertFrom-Json
            | Select-Object -expand value

            Write-Verbose -Message "Found $($assignedAppRolesForServicePrincipal.Length) assigned identities for $($enterpriseAppRegistration.id)."
        $roleAssignmentsForAllApplications += foreach($assignedAppRole in $assignedAppRolesForServicePrincipal) {
            $role = $servicePrincipalAppRoles | Where-Object{ $_.id -eq $assignedAppRole.appRoleId}
            Write-Verbose -Message "Adding $($role.displayName) to collection for $($assignedAppRole.principalDisplayName) on application $($enterpriseAppRegistration.displayName)."
            New-Object PsObject -Property @{
                AppRoleId = $assignedAppRole.appRoleId
                AppRoleDisplayName = $role.displayName
                PrincipalObjectId = $assignedAppRole.principalId
                PrincipalDisplayName = $assignedAppRole.principalDisplayName
                ApplicationDisplayName = $enterpriseAppRegistration.displayName
                ApplicationApplicationId = $enterpriseAppRegistration.appId
                ApplicationObjectId = $enterpriseAppRegistration.id
            }
        }
    }
    return $roleAssignmentsForAllApplications
}
#Login
Get-AppRoleAssignments -Verbose | Sort-Object -Property ApplicationDisplayName | Format-Table -Property ApplicationDisplayName, ApplicationApplicationId, ApplicationObjectId, PrincipalObjectId, PrincipalDisplayName, AppRoleId, AppRoleDisplayName | Out-File "AppRoleAssignments.md"

The output looks pretty much like this

Read more →