Query Details
let query_frequency = 1h;
let query_period = 14d;
IdentityInfo
| where TimeGenerated > ago(query_period)
| where set_has_element(AssignedRoles, "Global Administrator")
| distinct AccountUPN, AccountObjectId
| join kind=inner (
AuditLogs
| where TimeGenerated > ago(query_frequency)
| where OperationName=~ "Update user" and Result =~ "success"
// | where isnotempty(InitiatedBy["user"])
| mv-expand TargetResource = TargetResources
| where TargetResource["type"] == "User"
| extend AccountObjectId = tostring(TargetResource["id"])
| where not(tostring(TargetResource["modifiedProperties"]) == "[]")
| mv-apply modifiedProperty = TargetResource["modifiedProperties"] on (
summarize modifiedProperties = make_bag(
bag_pack(tostring(modifiedProperty["displayName"]),
bag_pack("oldValue", trim(@'[\"\s]+', tostring(modifiedProperty["oldValue"])),
"newValue", trim(@'[\"\s]+', tostring(modifiedProperty["newValue"])))))
)
| where not(tostring(modifiedProperties["Included Updated Properties"]["newValue"]) in ("LastDirSyncTime", ""))
| where not(tostring(modifiedProperties["Included Updated Properties"]["newValue"]) == "StrongAuthenticationPhoneAppDetail" and isnotempty(modifiedProperties["StrongAuthenticationPhoneAppDetail"]) and tostring(array_sort_asc(extract_all(@'\"Id\"\:\"([^\"]+)\"', tostring(modifiedProperties["StrongAuthenticationPhoneAppDetail"]["newValue"])))) == tostring(array_sort_asc(extract_all(@'\"Id\"\:\"([^\"]+)\"', tostring(modifiedProperties["StrongAuthenticationPhoneAppDetail"]["oldValue"])))))
| extend
Initiator = iif(isnotempty(InitiatedBy["app"]), tostring(InitiatedBy["app"]["displayName"]), tostring(InitiatedBy["user"]["userPrincipalName"])),
InitiatorId = iif(isnotempty(InitiatedBy["app"]), tostring(InitiatedBy["app"]["servicePrincipalId"]), tostring(InitiatedBy["user"]["id"])),
IPAddress = tostring(InitiatedBy[tostring(bag_keys(InitiatedBy)[0])]["ipAddress"])
) on AccountObjectId
| project
TimeGenerated,
Category,
Identity,
Initiator,
IPAddress,
OperationName,
Result,
AccountUPN,
InitiatedBy,
AdditionalDetails,
TargetResources,
AccountObjectId,
InitiatorId,
CorrelationId
This query is designed to track changes made to user accounts by global administrators in a system over a period of 14 days. It specifically looks for successful "Update user" operations.
The query first identifies accounts with the role of "Global Administrator". Then, it joins this data with audit logs that show successful user updates within the last hour.
The query also expands and filters the data to only include updates where the modified properties of the user account are not empty. It excludes updates related to "LastDirSyncTime", empty updates, and updates related to "StrongAuthenticationPhoneAppDetail" that have not changed the ID.
Finally, the query identifies the initiator of the update, whether it's a user or an app, and their corresponding ID and IP address. The result is a detailed report of all user updates, including the time of the operation, the category, the identity of the user, the initiator, the IP address, the operation name, the result, the account UPN, who initiated the operation, any additional details, the target resources, the account object ID, the initiator ID, and the correlation ID.

Jose Sebastián Canós
Released: May 23, 2023
Tables
Keywords
Operators