Query Details
// Function to get privileged users from IdentityInfo and privileged workloads from WorkloadIdentityInfo
let SensitiveEntraDirectoryRoles = externaldata(RoleName: string, RoleId: string, isPrivileged: bool, Classification: dynamic)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_EntraIdDirectoryRoles.json"] with(format='multijson')
| where Classification.EAMTierLevelName != "Unclassified"
| project RoleName, isPrivileged, Classification;
let SensitiveUsers = IdentityInfo
| where TimeGenerated > ago(14d)
| summarize arg_max(TimeGenerated, *) by AccountObjectId
| mv-expand AssignedRoles
| extend RoleName = tostring(AssignedRoles)
| join kind=inner ( SensitiveEntraDirectoryRoles ) on RoleName
| summarize Classification = make_set(parse_json(Classification.EAMTierLevelName)), RoleAssignments = make_set(RoleName) by AccountObjectId, AccountDisplayName, OnPremisesAccountObjectId;
let PrivilegedUsers = SensitiveUsers
| extend OnPremSynchronized = iff(isnotempty(OnPremisesAccountObjectId), "true", "false")
| project
ObjectId = tostring(AccountObjectId),
ObjectType = "User",
ObjectDisplayName = AccountDisplayName,
OnPremSynchronized,
tostring(Classification),
EntraIdRoles = RoleAssignments;
let PrivilegedWorkloads = WorkloadIdentityInfo
| where isnotempty(EntraIdRoles) or isnotempty(AppRolePermissions)
| project
ObjectId = tostring(ServicePrincipalObjectId),
ObjectType = WorkloadIdentityType,
ObjectDisplayName = WorkloadIdentityName,
OnPremSynchronized = "false",
Classification = tostring(EnterpriseAccessModelTiering),
EntraIdRoles = EntraIdRoles,
AppRoles = AppRolePermissions;
union PrivilegedUsers, PrivilegedWorkloadsThis query retrieves privileged users and privileged workloads from two different datasets.
First, it gets privileged users from the IdentityInfo dataset by filtering for users whose TimeGenerated is within the last 14 days. It then expands the AssignedRoles column, joins it with the SensitiveEntraDirectoryRoles dataset based on the RoleName, and summarizes the results by AccountObjectId, AccountDisplayName, and OnPremisesAccountObjectId.
Next, it creates a new dataset called PrivilegedUsers by selecting specific columns from the SensitiveUsers dataset and adding a column called OnPremSynchronized.
Finally, it retrieves privileged workloads from the WorkloadIdentityInfo dataset by filtering for workloads that have non-empty EntraIdRoles or AppRolePermissions. It selects specific columns and adds a column called OnPremSynchronized.
The query then combines the PrivilegedUsers and PrivilegedWorkloads datasets using the union operator.

Thomas Naunheim
Released: October 28, 2023
Tables
Keywords
Operators