Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions scripts/aad-audit-directory-role-assignments/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Audit Azure AD (Entra ID) Role Assignments

## Summary

This script audits all privileged Entra ID directory role assignments across a Microsoft 365 tenant using Microsoft Graph. It enumerates role assignments (direct and group-based), resolves the assigned principals (users, groups, service principals), and exports a clean, audit-ready report suitable for large tenants.

## Why It Matters

Security reviews, compliance attestations, and least-privilege initiatives require a single source of truth for who holds privileged access. Over time, directory roles are often granted via groups, inherited, or left assigned to inactive identities. This audit provides the evidence needed to identify excessive privilege, remediate risk, and satisfy auditors.

## Benefits
- **Complete visibility** into privileged role assignments (not limited to currently activated roles).
- **Detects risky patterns** (guest users, service principals, group-based elevation).
- **Audit-ready output** for compliance and governance reviews.
- **Scales to large tenants** using Microsoft Graph paging.

# [PowerShell Script](#tab/pnpps)

```powershell

param(
[Parameter(Mandatory)]
[string]$OutputPath
)

Connect-MgGraph -Scopes @(
"RoleManagement.Read.Directory",
"Directory.Read.All",
"User.Read.All",
"Group.Read.All"
)

$roleDefinitions = Get-MgRoleManagementDirectoryRoleDefinition -All |
Select-Object Id, DisplayName

$roleDefinitionLookup = @{}
foreach ($rd in $roleDefinitions) {
$roleDefinitionLookup[$rd.Id] = $rd.DisplayName
}

$assignments = Get-MgRoleManagementDirectoryRoleAssignment -All

$results = foreach ($assignment in $assignments) {

$roleName = $roleDefinitionLookup[$assignment.RoleDefinitionId]

$principalType = $assignment.PrincipalType
$principalId = $assignment.PrincipalId

$principalName = $null
$principalUPN = $null
$principalAppId = $null

switch ($principalType) {
"User" {
$user = Get-MgUser -UserId $principalId -ErrorAction SilentlyContinue
if ($user) {
$principalName = $user.DisplayName
$principalUPN = $user.UserPrincipalName
}
}
"Group" {
$group = Get-MgGroup -GroupId $principalId -ErrorAction SilentlyContinue
if ($group) {
$principalName = $group.DisplayName
}
}
"ServicePrincipal" {
$sp = Get-MgServicePrincipal -ServicePrincipalId $principalId -ErrorAction SilentlyContinue
if ($sp) {
$principalName = $sp.DisplayName
$principalAppId = $sp.AppId
}
}
}

[PSCustomObject]@{
RoleName = $roleName
RoleDefinitionId= $assignment.RoleDefinitionId
AssignmentId = $assignment.Id
AssignmentType = if ($assignment.PrincipalType -eq "Group") { "GroupBased" } else { "Direct" }
PrincipalType = $principalType
PrincipalName = $principalName
UserPrincipalName = $principalUPN
AppId = $principalAppId
Scope = $assignment.DirectoryScopeId
}
}

$results |
Sort-Object RoleName, PrincipalType, PrincipalName |
Export-Csv -Path $OutputPath -NoTypeInformation

```

# [Usage](#tab/usage)

```powershell

# Prerequisites (once)
Install-Module Microsoft.Graph -Scope CurrentUser

# Permissions required (delegated or app):
# RoleManagement.Read.Directory, Directory.Read.All, User.Read.All, Group.Read.All

# Run
.\Audit-EntraRoleAssignments.ps1 -OutputPath ".\EntraRoleAssignments.csv"

```

[!INCLUDE [More about PnP PowerShell](../../docfx/includes/MORE-PNPPS.md)]
***

## Output
The CSV report includes the following fields:
- Role name and scope.
- Assignment type (Direct / Group).
- Principal type (User / Group / ServicePrincipal).
- Principal details (UPN/AppId/DisplayName).
- Assignment ID.

## Notes
- Group-based assignments list the **group** as the principal (by design). Expand group membership separately if needed.
- PIM **eligibility vs active** can be added by querying PIM endpoints if required.

## Contributors

| Author(s) |
|-----------|
| [Josiah Opiyo](https://github.com/ojopiyo) |

*Built with a focus on automation, governance, least privilege, and clean Microsoft 365 tenants—helping M365 admins gain visibility and reduce operational risk.*


## Version history

Version|Date|Comments
-------|----|--------
1.0|Jan 03, 2026|Initial release


[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)]
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/aad-audit-directory-role-assignments" aria-hidden="true" />
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 55 additions & 0 deletions scripts/aad-audit-directory-role-assignments/assets/sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[
{
"name": "aad-audit-directory-role-assignments",
"source": "pnp",
"title": "Audit Azure AD (Entra ID) Role Assignments",
"shortDescription": "This script audits all privileged Entra ID directory role assignments across a Microsoft 365 tenant",
"url": "https://pnp.github.io/script-samples/aad-audit-directory-role-assignments/README.html",
"longDescription": [
""
],
"creationDateTime": "2026-01-03",
"updateDateTime": "2026-01-03",
"products": [
"Graph"
],
"metadata": [
{
"key": "GRAPH-POWERSHELL",
"value": "1.0.0"
}
],
"categories": [
"Report"
],
"tags": [
"Get-MgRoleManagementDirectoryRoleAssignment",
"Get-MgRoleManagementDirectoryRoleDefinition",
"Get-MgUser",
"Get-MgGroup"
],
"thumbnails": [
{
"type": "image",
"order": 100,
"url": "https://raw.githubusercontent.com/pnp/script-samples/main/scripts/aad-audit-directory-role-assignments/assets/preview.png",
"alt": "Preview of the sample Audit Azure AD (Entra ID) Role Assignments"
}
],
"authors": [
{
"gitHubAccount": "ojopiyo",
"company": "",
"pictureUrl": "https://github.com/ojopiyo.png",
"name": "Josiah Opiyo"
}
],
"references": [
{
"name": "Want to learn more about Microsoft Graph PowerShell SDK and the cmdlets",
"description": "Check out the Microsoft Graph PowerShell SDK documentation site to get started and for the reference to the cmdlets.",
"url": "https://learn.microsoft.com/graph/powershell/get-started"
}
]
}
]