Entra / Microsoft 365 · Applications
Report service principals with high permissions
How to scan the assignments for highly-privileged Entra ID roles and report the service principals (apps).
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -NoWelcome -Scopes RoleManagement.Read.Directory, Group.Read.All, ServicePrincipal.Read.All
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
Connect-MgGraph -NoWelcome -Scopes RoleManagement.Read.Directory, Group.Read.All, ServicePrincipal.Read.All# Find the Entra roles marked as highly privileged[array]$PrivilegedRoles = Get-MgBetaRoleManagementDirectoryRoleDefinition -Filter "isPrivileged eq true" -All -PageSize 500If (!$HighlyPrivilegedRoles) {Write-Host "No highly privileged roles found"Exit}# Create a hash table to store the highly privileged roles - it's faster to search a hash table than an array$HighlyPrivilegedRoles = @{}ForEach ($Role in $PrivilegedRoles) {$HighlyPrivilegedRoles.Add($Role.Id, $Role.DisplayName)}# Create arrays of service principals, role assignments, and groupsWrite-Host "Fetching details of service principals, groups, and role assignments..."[array]$ServicePrincipals = Get-MgServicePrincipal -All -PageSize 500[array]$RoleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -All -PageSize 500[array]$GroupArray = Get-MgGroup -All -Property Id, displayName -PageSize 500# Create the output report$Report = [System.Collections.Generic.List[Object]]::new()# Check each role assignment to see if it's for a highly privileged roleWrite-Host "Starting to check service principals for highly privileged roles..."ForEach ($Assignment in $RoleAssignments) {If ($HighlyPrivilegedRoles.ContainsKey($Assignment.RoleDefinitionId)) {$ServicePrincipal = $ServicePrincipals | Where-Object {$_.Id -eq $Assignment.PrincipalId}If ($ServicePrincipal) {$DataLine = [PSCustomObject][Ordered]@{ServicePrincipalId = $ServicePrincipal.IdServicePrincipalName = $ServicePrincipal.DisplayNameRoleDefinitionId = $Assignment.RoleDefinitionIdRoleDefinitionName = $HighlyPrivilegedRoles[$Assignment.RoleDefinitionId]ServicePrincipalType = $ServicePrincipal.ServicePrincipalType}$Report.Add($DataLine)}# Check if the assignment is for a group$PrivilegedGroup = $GroupArray | Where-Object {$_.Id -contains $Assignment.PrincipalId}If ($PrivilegedGroup) {# Get the membership of the group - it could be transitive, so that's what we use$PrivilegedGroupMembers = Get-MgGroupTransitiveMember -GroupId $PrivilegedGroup.Id -All$DataLine = [PSCustomObject][Ordered]@{ServicePrincipalId = $PrivilegedGroup.IdServicePrincipalName = $PrivilegedGroup.DisplayNameRoleDefinitionId = $Assignment.RoleDefinitionIdRoleDefinitionName = $HighlyPrivilegedRoles[$Assignment.RoleDefinitionId]ServicePrincipalType = "Group"Members = $PrivilegedGroupMembers.additionalProperties.displayName -join ", "}$Report.Add($DataLine)}}}$Report | Format-table ServicePrincipalId, ServicePrincipalName, RoleDefinitionName, ServicePrincipalType, Members -AutoSize
Attribution
Author
Office365itpros