I am searching for EventID 4738 logs in the SecurityEvents table in sentinel. This log has several fields which contain either the new value if it was changed, or "-" if it wasn't changed.
I want to pack these fields into one dynamic object which only contains the KV pairs where the value is not "-". I have currently got this query which uses the bag_pack_columns function:
SecurityEvent
| where TimeGenerated > ago(7d)
| where EventID == 4738
| where TargetUserName in~ ((
_GetWatchlist('sensitive-accounts')
| project SearchKey
))
| extend ChangedFields = bag_pack_columns(AccountExpires, AllowedToDelegateTo, DisplayName, HomeDirectory, HomePath, LogonHours, NewUacValue, OldUacValue, PasswordLastSet, PrimaryGroupId, PrivilegeList, ProfilePath, SamAccountName, ScriptPath, SidHistory, UserAccountControl, UserParameters, UserPrincipalName, UserWorkstations)
| project TimeGenerated, SubjectUserName, TargetUserName, ChangedFields
This returns results similar to the below, which packs all the fields, including the "-" ones:
| TimeGenerated | SubjectUserName | TargetUserName | ChangedFields |
|---|---|---|---|
| 2025-11-21T16:38:59.4756574Z | AdminUser1 | SensitiveUser1 | {"AccountExpires":"-","AllowedToDelegateTo":"-","DisplayName":"-","HomeDirectory":"-","HomePath":"-","LogonHours":"-","NewUacValue":"-","OldUacValue":"-","PasswordLastSet":"21/11/2025 16:38:59","PrimaryGroupId":"-","PrivilegeList":"-","ProfilePath":"-","SamAccountName":"-","ScriptPath":"-","SidHistory":"-","UserAccountControl":"-","UserParameters":"-","UserPrincipalName":"-","UserWorkstations":"-"} |
| 2025-11-21T16:35:49.0817969Z | AdminUser2 | SensitiveUser2 | {"AccountExpires":"-","AllowedToDelegateTo":"-","DisplayName":"-","HomeDirectory":"-","HomePath":"-","LogonHours":"-","NewUacValue":"0x10","OldUacValue":"0x11","PasswordLastSet":"-","PrimaryGroupId":"-","PrivilegeList":"-","ProfilePath":"-","SamAccountName":"-","ScriptPath":"-","SidHistory":"-","UserAccountControl":" \t\t%%2048","UserParameters":"-","UserPrincipalName":"-","UserWorkstations":"-"} |
What I want is something like this hypotheical bag_pack_columns_if:
| extend ChangedFields = bag_pack_columns_if(Value != "-", AccountExpires, AllowedToDelegateTo, DisplayName, HomeDirectory, HomePath, LogonHours, NewUacValue, OldUacValue, PasswordLastSet, PrimaryGroupId, PrivilegeList, ProfilePath, SamAccountName, ScriptPath, SidHistory, UserAccountControl, UserParameters, UserPrincipalName, UserWorkstations)
Which would ideally return something like this:
| TimeGenerated | SubjectUserName | TargetUserName | ChangedFields |
|---|---|---|---|
| 2025-11-21T16:38:59.4756574Z | AdminUser1 | SensitiveUser1 | {"PasswordLastSet":"21/11/2025 16:38:59"} |
| 2025-11-21T16:35:49.0817969Z | AdminUser2 | SensitiveUser2 | {"NewUacValue":"0x10","OldUacValue":"0x11","UserAccountControl":" \t\t%%2048"} |
Is there a KQL function that works like this?