In this post I will quickly demo how to use PowerShell to get app role assignments for all application using the Microsoft Graph.
You should have followed my previous post in order to have created an application, added some appRoles to the manifest and granted access to the Graph.
Let’s recap the important parts:
1 – Create an enterprise application in Azure AD
2 – Go to “app registrations”, find the app and add appRoles to the manifest
The following are provided by default, disable those and add some custom ones. See the below example roles.
{
"allowedMemberTypes": [
"User"
],
"description": "Superuser",
"displayName": "Superuser",
"id": "1c55497a-32ec-4f17-a33e-a7157deb8d72",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "Superuser"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Administrator",
"displayName": "Administrator",
"id": "62f71d53-5152-48fb-9e0e-be121f4fd736",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "Administrator"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Frontline",
"displayName": "Frontline",
"id": "e580e3b7-1e4e-4c15-b820-256d36f60e68",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "Frontline"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Manager",
"displayName": "Manager",
"id": "25864c8d-637b-4ce1-8283-e3c3678669ce",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "Manager"
}
3 – Go back to enterprise applications and assign users some roles

4 – Grant access to the required Graph resources
Go to app registrations, find the application and go to “API permissions”. Click “Add a permission”:

Select the Microsoft Graph:

Choose Application permissions, as we are doing things without a user context:

Add “User.Read.All” and “Group.Read.All” and click save.


You will see that the added permissions now have “Not granted for <Organization>” as status. Click “Grant admin consent for <Organization>” in order to enable these new permissions:

This is what it should look like:

5 – Request data with PowerShell
First, generate a secret under app registrations in Azure AD. This is the $secret variable in the below PowerShells.

Go the enterprise application and copy the “Application ID” – this is the $clientid variable in the below PowerShells.
Copy “Object ID” – this is the $servicePrincipalId variable in the below PowerShells.

The $tenant variable can be either any custom domain registered in the tenant, the default domain or the tenant id (you can find it here) found on the app registrations page on your application.
The first example PowerShell will return a simple grid view with a multi valued column containing the roles of each assigned object. The script will not dig into the group members.
$clientid = "dd54e8b7-8c69-435a-a460-e7041f98ee30"
$secret = "HCtl:g:DFAc65BNpW0IUS6smY/tc@ARo"
$tenant = "e88da32e-db23-4b1e-af95-f808ac863371"
$servicePrincipalId = "60abe170-b93b-4c1b-b252-79d6667e468a"
Write-Verbose "Requesting token using client credential grant" -Verbose
$token = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenant/oauth2/v2.0/token" -Method Post -Body "client_id=$clientid&scope=https://graph.microsoft.com/.default&client_secret=$secret&grant_type=client_credentials"
if($token.access_token) {
Write-Verbose "Received access token: $($token.access_token)" -Verbose
} else {
Read-Host "Could not find access token, check your settings"
}
$params = @{Headers = @{Authorization = "bearer $($token.access_token)"}}
# Get app manifest and build app role map
Write-Verbose "Fetching app manifest for service principal $servicePrincipalId" -Verbose
$servicePrincipalGraphResponse = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/servicePrincipals/$servicePrincipalId" @params
$appRolesMap = $servicePrincipalGraphResponse.appRoles | Foreach -Begin {$h = @{}} -End {$h} -Process {$h[$_.id] = $_}
# Get all app role assignments
$uri = "https://graph.microsoft.com/beta/servicePrincipals/$servicePrincipalId/appRoleAssignments"
$appRoleAssignments = @()
do {
Write-Verbose "Getting app role assignments: $uri" -Verbose
$response = Invoke-RestMethod -Uri $uri @params
$uri = $response."nextLink"
$appRoleAssignments += $response.value
} while($uri -ne $null)
$appRoleAssignments |
group principalId |
foreach {
[PSCustomObject] @{
DisplayName = $_.group.principalDisplayName | select -First 1
Type = $_.group.principalType | select -First 1
RoleIDs = $_.group.appRoleId RoleDisplayNames = $_.group.appRoleId | foreach{$appRolesMap[$_].DisplayName}
RoleValues = $_.group.appRoleId | foreach{$appRolesMap[$_].Value}
}
} | Out-GridView
And here is an example for you that also digs into the different assigned groups and fetches all transitive members of those:
$clientid = "dd54e8b7-8c69-435a-a460-e7041f98ee30"
$secret = "HCtl:g:DFAc65BNpW0IUS6smY/tc@ARo"
$tenant = "e88da32e-db23-4b1e-af95-f808ac863371"
$servicePrincipalId = "60abe170-b93b-4c1b-b252-79d6667e468a"
Write-Verbose "Requesting token using client credential grant" -Verbose
$token = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenant/oauth2/v2.0/token" -Method Post -Body "client_id=$clientid&scope=https://graph.microsoft.com/.default&client_secret=$secret&grant_type=client_credentials"
if($token.access_token) {
Write-Verbose "Received access token: $($token.access_token)" -Verbose
} else {
Read-Host "Could not find access token, check your settings"
}
$params = @{Headers = @{Authorization = "bearer $($token.access_token)"}}
# Get all users
$users = @()
$uri = "https://graph.microsoft.com/beta/users"
do {
Write-Verbose "Getting all users: $uri" -Verbose
$response = Invoke-RestMethod -Uri $uri @params
$uri = $response."nextLink"
$users += $response.value
} while($uri -ne $null)
$usersMap = $users | group -AsHashTable -Property id -AsString
# Get app manifest and build app role map
Write-Verbose "Fetching app manifest for service principal $servicePrincipalId" -Verbose
$servicePrincipalGraphResponse = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/servicePrincipals/$servicePrincipalId" @params
$appRolesMap = $servicePrincipalGraphResponse.appRoles | Foreach -Begin {$h = @{}} -End {$h} -Process {$h[$_.id] = $_}
# Get all app role assignments
$uri = "https://graph.microsoft.com/beta/servicePrincipals/$servicePrincipalId/appRoleAssignments"
$appRoleAssignments = @()
do {
Write-Verbose "Getting app role assignments: $uri" -Verbose
$response = Invoke-RestMethod -Uri $uri @params
$uri = $response."nextLink"
$appRoleAssignments += $response.value
} while($uri -ne $null)
# Process group memberships to get a full list of assigned users
$appRoleAssignmentsTransitive = $appRoleAssignments |
foreach {
if($_.principalType -eq "Group") {
$assignment = $_
# Get all users
$uri = "https://graph.microsoft.com/beta/groups/$($_.principalId)/transitiveMembers"
do {
Write-Verbose "Getting members of group $($_.principalId): $uri" -Verbose
$response = Invoke-RestMethod -Uri $uri @params
$uri = $response."nextLink"
$response.value |
where '@odata.type' -eq '#microsoft.graph.user' |
foreach {
[PSCustomObject] @{
appRoleId = $assignment.appRoleId
principalId = $_.id
principalType = "User"
resourceId = $assignment.resourceId
resourceDisplayName = $assignment.resourceDisplayName
creationTimeStamp = $assignment.creationTimestamp
id = [Guid]::NewGuid()
}
}
} while($uri -ne $null)
} else {
$_
}
}
$ExcelFile = "~\desktop\$([guid]::newguid()).xlsx"
Write-Verbose "Writing Excel file $ExcelFile" -Verbose
$appRoleAssignmentsTransitive |
group principalId |
foreach {
[PSCustomObject] @{
UserObjectID = $_.name
DisplayName = $UsersMap[$_.name].DisplayName
Mail = $UsersMap[$_.name].Mail
RoleIDs = $_.group.appRoleId -join ","
RoleDisplayNames = ($_.group.appRoleId | foreach{$appRolesMap[$_].DisplayName}) -join ","
RoleValues = ($_.group.appRoleId | foreach{$appRolesMap[$_].Value}) -join ","
}
} |
Export-Excel -Path $ExcelFile -AutoFilter -AutoSize -FreezeTopRow ii $ExcelFile
That’s it, I have now gone through three ways of getting the application role assignments from Azure AD into your application:
- SCIM provisioning
- At sign in (OAuth ID Token or SAML Claim)
- Fetching by Graph calls
The next posts will focus on how to actually manage application role assignments, dynamically assigning, using Entitlement Management to allow both internal and invited users to request access and other means. Stay tuned!
One thought on “Full IGA using Azure AD – Getting app role assignments using PowerShell”