KQL - bag_pack_columns if column not empty
14:03 21 Nov 2025

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?

kql azure-sentinel