Building Bulletproof Sentinel Queries: The Universal EventData XML Parser Pattern

Microsoft Sentinel · KQL Deep Dive

Stop fragile index-based XML parsing and switch to a universal, future-proof EventData parser that works across all Windows event types in Microsoft Sentinel.

If you’ve ever worked with the Event table in Microsoft Sentinel or Azure Monitor Logs, you already know the pain:

  • EventData is XML and every event type uses a different schema.
  • Most examples use fragile array indexes like Data[7]['#text'].
  • This post gives you a universal KQL pattern that dynamically parses all <Data> fields.
  • No index guessing, no hardcoding, and it works across multiple Event IDs.

Why the Usual Way of Parsing EventData Fails

Traditionally, analysts parse XML like this:

extend ThreatName = parse_xml(EventData).DataItem.EventData.Data[7]['#text']

Problems with this approach:

  • Fragile – If Microsoft adds or reorders <Data> fields, everything breaks.
  • Event-specific – Works only for one Event ID or one schema.
  • Hard to maintain – Counting indexes destroys readability.
  • Not scalable – You must rewrite the parser for each event type.

🔥 The Universal EventData XML Parser (KQL)

// Universal EventData XML parser for the Event table
Event
| where TimeGenerated >= ago(24h)
| extend ParsedEventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand ParsedEventData
| extend
    FieldName  = tostring(ParsedEventData['@Name']),
    FieldValue = tostring(ParsedEventData['#text'])
| evaluate pivot(FieldName, any(FieldValue), TimeGenerated, Computer, EventID)

This query extracts every field inside EventData, automatically names columns using <Data Name="...">, works across all event IDs, and requires zero editing when the XML structure changes.

Optional: Wrap Into a Reusable Function

let parse_eventdata = (input:(TimeGenerated:datetime, Computer:string, EventID:int, EventData:string)) {
    input
    | extend ParsedEventData = parse_xml(EventData).DataItem.EventData.Data
    | mv-expand ParsedEventData
    | extend
        FieldName  = tostring(ParsedEventData['@Name']),
        FieldValue = tostring(ParsedEventData['#text'])
    | evaluate pivot(FieldName, any(FieldValue), TimeGenerated, Computer, EventID)
};
// Usage
parse_eventdata(Event | where TimeGenerated >= ago(1d))

Performance Tips

  • Always use a time filter (e.g., ago(24h) or smaller).
  • Filter by EventLog or EventID before parsing where possible.
  • Avoid parsing months of raw EventData at once unless absolutely required.

Final Thoughts

This universal parser is one of the most powerful ways to work with Windows Event Logs in Microsoft Sentinel. It simplifies analysis, enhances detection engineering, and eliminates the brittle, outdated practice of index-based XML parsing.

If you work with Sentinel long enough, this quickly becomes one of your core KQL tools — something you reuse across detections, hunting queries, and incident investigations.


Need Expert Help with Microsoft Sentinel?

Whether you’re building detections, optimizing costs, or setting up your SOC — SecByte offers hands-on Microsoft Sentinel consultancy, training, and architecture support.

Responses to “Building Bulletproof Sentinel Queries: The Universal EventData XML Parser Pattern”

  1. That’s great, thanks for this parser, really useful. That being said, I noticed it does not work for SQL Server events stored in Security Event Log. The function drops most of the data

    1. Thanks for the comment. In SecurityEvent logs are already parsed so you no need to use parser for that.

Leave a Reply to Sylvain HamelCancel reply

Discover more from SecByte

Subscribe now to keep reading and get access to the full archive.

Continue reading