Privileged directory role assigned outside PIM workflow
Description
Identifies permanent directory role assignments to privileged roles made outside the Privileged Identity Management activation workflow. Direct assignments bypass PIM approval and justification requirements.
Query · kql
let timeframe = 14d;
let PrivilegedRoles = dynamic([
"Global Administrator",
"Privileged Role Administrator",
"Application Administrator",
"Cloud Application Administrator",
"Exchange Administrator",
"SharePoint Administrator",
"User Account Administrator",
"Authentication Administrator",
"Privileged Authentication Administrator",
"Security Administrator",
"Hybrid Identity Administrator"
]);
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where Category =~ "RoleManagement"
| where OperationName =~ "Add member to role."
| where Result =~ "success"
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| extend TargetUpn = tostring(TargetResources[0].userPrincipalName)
| extend TargetId = tostring(TargetResources[0].id)
| mv-expand ModProp = TargetResources[0].modifiedProperties
| where tostring(ModProp.displayName) =~ "Role.DisplayName"
| extend RoleName = trim('"', tostring(ModProp.newValue))
| where RoleName in~ (PrivilegedRoles)
| extend ActorName = iff(ActorUpn has "@", tostring(split(ActorUpn, "@")[0]), Actor)
| extend ActorUPNSuffix = iff(ActorUpn has "@", tostring(split(ActorUpn, "@")[1]), "")
| extend AccountName = iff(TargetUpn has "@", tostring(split(TargetUpn, "@")[0]), TargetUpn)
| extend AccountUPNSuffix = iff(TargetUpn has "@", tostring(split(TargetUpn, "@")[1]), "")
| project TimeGenerated, Actor, ActorName, ActorUPNSuffix, ActorIp,
TargetUpn, AccountName, AccountUPNSuffix, TargetId, RoleName, CorrelationId
| sort by TimeGenerated desc