Skip to main content

Retrieving Role Assignments with PowerShell

ยท 5 min read
Hasan Gural

Hey folks,

In this post, I want to get into Role Assignments that have been made at the subscription scope or more specifically, at the resource group or resource level, and try to analyze and generate a report for them. Microsoft has enhanced the Resource Graph to retrieve assignments directly through Resource Graph queries, whereas previously we were doing it via PowerShell.

Retrieving Role Assignments with PowerShell

When attempting to retrieve role assignments for specific scopes downstream of the subscription, the process using PowerShell truly becomes a hassle. I found myself relying on the Get-AzRoleAssignment cmdlet to fetch role assignments at the subscription scope, followed by additional filtering for the resource group or resource level. However, with the recent enhancements to the Azure Resource Graph, we can now directly query role assignments for specific scopes. A slight tweak to the query is all that's needed to achieve the desired results.

๐Ÿ”Ž Query Role Assignments with Azure Resource Graphโ€‹

I've previously shared on the blog the power of the Azure Resource Graph for listing/reporting a variety of network resources, such as VNet peering, network security groups, and more. I think I can jump straight into the topic of which table we will use for retrieving role assignments in a specific scope for its downstream resources.

| where type =~ "microsoft.authorization/roleassignments"
| where id startswith "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

If we begin to execute the above Azure Resource Graph clause, we'll gather bunch of information about the assignments, including the scope they've been made in, as well as details like the scopeId, principalId, roleDefinitionId and more. My intention is to use these values to build something upon on it. I will use PowerShell to generate a report that I want to have end of the day.

๐Ÿ’ป Generate Role Assignment Report with PowerShellโ€‹

I've dedicated some time to carving out a module that leverages both Az.Graph and Microsoft.Graph to generate a report. This report finds all PrincipalId with their corresponding DisplayNames, making it far more readable than just listing PrincipalId for each assignment.

Here's the PowerShell script - before you execute it, there are a few prerequisites you should know:

  • The Az.Graph and Az.Accounts modules must be installed.
  • The Microsoft.Graph.DirectoryObjects module must be installed.
  • Of course, you need to authenticate with Connect-AzAccount.
  • Connect-MgGraph must be executed to authenticate with Microsoft Graph.Connect-MgGraph -Scopes "Directory.Read.All

Report Layout is as follows:

roleDefinitionName = "Role Definition Name"
roleDefinitionId = "Role Definition Id"
principalId = "Principal Id"
displayName = "Display Name"
createdOn = "Created On"
updatedOn = "Updated On"
scope = "Scope"
A script to retrieve all role assignments within an Azure subscription using Azure Resource Graph.

"Get-AzActiveRoleAssignments.ps1" is designed PowerShell script that leverages the Azure Resource Graph and Microsoft Graph to fetch all role assignments for a specified Azure subscription.

.PARAMETER subscriptionId
The ID of the Azure subscription for which you want to retrieve role assignments.

CSV file named "AzureRoleAssignments.csv". This file contains detailed information about each role assignment, including the role name, principal name, assignment scope, and more.

PS> .\Get-AzActiveRoleAssignments.ps1 -SubscriptionId "your-subscription-id-here"

Executes the script to get all role assignments for the specified subscription and exports the results to "AzureRoleAssignments.csv".

Author: Hasan Gural
Version: BETAv1
Requires :
- Az.Graph
- Az.Accounts
- Az.Resources
- Microsoft.Graph.DirectoryObjects


param (

[Parameter(Mandatory = $true)]

$fileName = ($Script:MyInvocation.MyCommand.Name).Replace(".ps1",("-Report-")+(Get-Date -Format "yyyyMMdd-HHmmss") + ".csv")
Write-Output "INFO: Fetching Role Assignments for Subscription: $subscriptionId"

$query = @"
| where type =~ "microsoft.authorization/roleassignments"
| where id startswith "/subscriptions/$($subscriptionId)"
| extend RoleDefinitionId = tolower(tostring(properties.roleDefinitionId))
| extend PrincipalId = tolower(properties.principalId)
| extend RoleDefinitionId_PrincipalId = strcat(RoleDefinitionId, "_", PrincipalId)
| join kind = leftouter (
| where type =~ "microsoft.authorization/roledefinitions"
| extend RoleDefinitionName = tostring(properties.roleName)
| extend rdId = tolower(id)
| project RoleDefinitionName, rdId
on `$left.RoleDefinitionId == `$right.rdId
| extend scope = properties.scope
| extend createdOn = properties.createdOn
| extend updatedOn = properties.updatedOn
| project RoleDefinitionId = split(RoleDefinitionId_PrincipalId, "_", 0)[0], RoleDefinitionName, PrincipalId = split(RoleDefinitionId_PrincipalId, "_", 1)[0], scope, createdOn, updatedOn

$result = Search-AzGraph -Query $query

$listAssignments = @()

ForEach($assigment in $result){

$getPrincipalDisplayName = (Get-MgDirectoryObject -DirectoryObjectId $assigment.PrincipalId -ErrorAction SilentlyContinue | `
Select-Object -ExpandProperty AdditionalProperties).displayName

$obj = [PSCustomObject]@{

roleDefinitionName = $assigment.RoleDefinitionName
roleDefinitionId = $assigment.RoleDefinitionId
principalId = $assigment.PrincipalId
displayName = $getPrincipalDisplayName
createdOn = $assigment.createdOn
updatedOn = $assigment.updatedOn
scope = $assigment.scope


$listAssignments += $obj

Write-Output "INFO: Exporting Role Assignments to CSV file: $fileName"

$listAssignments | Export-Csv -Path $fileName -NoTypeInformation -Force

๐Ÿš€ Execute the Scriptโ€‹

To execute the script, simply provide the subscription ID as a parameter. The script will then fetch all role assignments for the specified subscription and export the results to a CSV file named Get-AzActiveRoleAssigments-Report-<DateTime>.csv.

.\Get-AzActiveRoleAssignments.ps1 -SubscriptionId "your-subscription-id-here"

Executing the Script

If you're looking to extend the script further, please share your thoughts and ideas we can implement together. Thanks for reading trough.