I wanted a way to report on current Entra ID principals in my tenant as well as the permissions granted to such principals across apps, the tenant directory and Azure subscriptions. Microsoft provides the separately licensed Entra Permissions Management which provides comprehensive principal and permissions discovery and reporting. I wanted something simpler.
The PowerShell script entra-id-principals-permissions-report.ps1 enumerates all principals and various permissions available in your current Azure CLI login context.
Warning
This script might export PII as well as potentially security sensitive information. Review the script and understand what it is doing before running it.
Export of all user, group and service principals. Each item includes the principal type
, id
, createdDateTime
, and displayName
. In addition a composite name
is added to uniquely identify the principal across tenants in a user readable way, and includes information about the owner tenant, publisher or Microsoft first-party application status.
Enumerating tenant users and groups is fairly simple. Service principals are slightly more complex, since I wanted to also know with some confidence the owning organization (home tenant) and publisher of service principals for multi-tenant applications.
- Service principals include
appOwnerOrganizationId
, but that is a GUID which doesn't really tell us much. Microsoft has some documentation on verifying Microsoft first-party applications, but that does not help with other tenants. Fortunately we can findTenantInformationByTenantId to resolve the default domain and display name of the associated tenant. - However not all apps include this owner information. We can also check the verified publisher to gain insights into the owning organization.
- Not all apps include either of these, and most seem to be Microsoft first-party applications. How can we determine if an application is such a first-party application? Microsoft Graph does not give us this information, but the Azure AD legacy API includes the
microsoftFirstParty
property, which is also used by the Entra ID portal to indicate if an application is a Microsoft first-party application.
Example
[
{
"type": "User",
"id": "00000000-0000-0000-0000-000000000000",
"createdDateTime": "2025-01-02T03:04:05Z",
"displayName": "Test User",
"name": "Tenant([email protected])/User:[email protected]"
},
{
"type": "Group",
"id": "00000000-0000-0000-0000-000000000000",
"createdDateTime": "2025-01-02T03:04:05Z",
"displayName": "Test Group",
"name": "Tenant([email protected])/Group:Test Group"
},
{
"type": "ServicePrincipal",
"id": "00000000-0000-0000-0000-000000000000",
"createdDateTime": "2025-01-02T03:04:05Z",
"displayName": "Microsoft Cloud App Security",
"name": "Tenant(Microsoft [email protected])/Application:Microsoft Cloud App Security"
},
{
"type": "ServicePrincipal",
"id": "00000000-0000-0000-0000-000000000000",
"createdDateTime": "2025-01-02T03:04:05Z",
"displayName": "PowerApps Service",
"name": "MicrosoftFirstParty(Microsoft Corporation)/Application:PowerApps Service"
},
{
"type": "ServicePrincipal",
"id": "00000000-0000-0000-0000-000000000000",
"createdDateTime": "2025-01-02T03:04:05Z",
"displayName": "CloudPosture/securityOperators/DefenderCSPMSecurityOperator",
"name": "Tenant([email protected])/ManagedIdentity/SystemAssigned:/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Security/pricings/CloudPosture/securityOperators/DefenderCSPMSecurityOperator"
}
]
Export of app, directory and Azure permissions granted to principals. Each item includes the principal unique name, the permission description (app role assignment role name, OAuth2 scope and client name, or directory role definition name), target resource type and unique name. The following permissions are exported:
- App role assignments granted to users, groups and service principals.
- User delegated permission grants (OAuth2 scopes)
- Entra ID role assignments
- Azure subscription role assignments across all authorized subscriptions
Example
[
{
"principalName": "Tenant([email protected])/User:[email protected]",
"permission": "User.Read,User.ReadBasic.All@Tenant([email protected])/Application:Azure VPN",
"resourceType": "Principal:ServicePrincipal",
"resourceName": "Principal:Tenant(Microsoft [email protected])/Application:Microsoft Graph"
},
{
"principalName": "Tenant([email protected])/User:[email protected]",
"permission": "Application Administrator",
"resourceType": "Directory",
"resourceName": "Directory(contoso.onmicrosoft.com):/"
},
{
"principalName": "<Deleted>",
"permission": "AcrPush",
"resourceType": "Azure",
"resourceName": "Azure:/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-mycontainerregistry/providers/Microsoft.ContainerRegistry/registries/mycontainerregistry"
},
{
"principalName": "Tenant([email protected])/ManagedIdentity/UserAssigned:/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg-myidentity/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myidentity",
"permission": "Reader",
"resourceType": "Azure",
"resourceName": "Azure:/subscriptions/00000000-0000-0000-0000-000000000000"
},
{
"principalName": "Tenant([email protected])/ManagedIdentity/SystemAssigned:/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Security/dataScanners/storageDataScanner",
"permission": "Storage Blob Data Reader",
"resourceType": "Azure",
"resourceName": "Azure:/subscriptions/00000000-0000-0000-0000-000000000000"
}
]
A Mermaid flowchart of the previous permissions, as well as an SVG rendering of the flowchart.
Example
flowchart LR
subgraph Azure["Azure"]
a1["Azure:/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.ContainerRegistry/registries/acr"]
a2["Azure:/subscriptions/00000000-0000-0000-0000-000000000000"]
end
subgraph Directory["Directory"]
d1["Directory(contoso.onmicrosoft.com):/"]
end
subgraph ServicePrincipal["Principal:ServicePrincipal"]
sp1["Principal:Tenant(Microsoft@microsoft.onmicrosoft.com)/Application:Azure VPN"]
sp2["Principal:Tenant(Microsoft Services@sharepoint.com)/Application:Microsoft Graph"]
end
p1["Tenant(contoso@contoso.onmicrosoft.com)/User:test.user@contoso.onmicrosoft.com"] -- "Application Administrator" --> d1["Directory(contoso.onmicrosoft.com):/"]
p1["Tenant(contoso@contoso.onmicrosoft.com)/User:test.user@contoso.onmicrosoft.com"] -- "AssignmentWithoutRole" --> sp1["Principal:Tenant(Microsoft@microsoft.onmicrosoft.com)/Application:Azure VPN"]
p1["Tenant(contoso@contoso.onmicrosoft.com)/User:test.user@contoso.onmicrosoft.com"] -- "Key Vault Administrator" --> a2["Azure:/subscriptions/00000000-0000-0000-0000-000000000000"]
p1["Tenant(contoso@contoso.onmicrosoft.com)/User:test.user@contoso.onmicrosoft.com"] -- "User.Read,User.ReadBasic.All@Tenant(Microsoft@microsoft.onmicrosoft.com)/Application:Azure VPN" --> sp2["Principal:Tenant(Microsoft Services@sharepoint.com)/Application:Microsoft Graph"]
p2["Tenant(contoso@contoso.onmicrosoft.com)/ManagedIdentity/SystemAssigned:/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Security/dataScanners/storageDataScanner"] -- "Storage Blob Data Reader" --> a2["Azure:/subscriptions/00000000-0000-0000-0000-000000000000"]
p3["MicrosoftFirstParty(Microsoft Corporation)/Application:Microsoft.Azure.SyncFabric"] -- "Directory Readers" --> d1["Directory(contoso.onmicrosoft.com):/"]
p4["<Deleted>"] -- "AcrPull" --> a1["Azure:/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.ContainerRegistry/registries/acr"]