Understand query property propagation in sentinel playbook

cyber punk 40 Reputation points
2026-11-03T11:18:29.2433333+00:00

Hi Team,

I'm trying to understand the source of the Query property that is being used in a Sentinel playbook and whether it's associated specifically with analytics rule-generated alerts.

Scenario:

I have a Sentinel playbook (Logic App) that contains a "Run query and list results" action.

The query parameter for that action is set to:

@body('Parse_JSON')['Query']

The value comes from a previous Parse JSON step.

When the playbook runs successfully, the Parse JSON output contains a property named Query with the following value:

let alertedEvent = datatable(compressedRec: string)

['eAFVjLEKwjAURf8ls4YkrVKyFQUpdHDo5BaSR3mQvJT01UX8d1Ocul3uPed+xIQJHkBQHEMQVhhlrmetzo2adGdNZ5WRl061baNf4iRuOS0bQxnzPEN10hLX4FUjE+CeZczexUrfc3JIR/aP1LH3Pm/Eh5XRQ3Se8Q1cqgqlgsM67n99SEjC0hZj7QgZHSPNw7N6WkljGqmk1lp8f6wdRT8=']

| extend raw = todynamic(zlib_decompress_from_base64_string(compressedRec))

| evaluate bag_unpack(raw)

| project-away compressedRec;

alertedEvent

The payload also contains the following properties:

{

"Analytic Rule Name": "AnalyticsRule_Unusual_DailyDrivers",

"Query Period": "00:10:00",

"Search Query Results Overall Count": "1",

"Event Grouping": "AlertPerEvent",

"ProcessedBySentinel": "True"

}

Observation

When I manually create a test incident from: Microsoft Sentinel → Incidents → Create Incident

and trigger the same playbook, it fails because the following property doesn't exist:

body('Parse_JSON')['Query']

The manually created incident payload does not contain a Query property.

My Questions:

  1. Is the Query property automatically added only when an incident originates from a Sentinel Analytics Rule alert?
  2. Is the let alertedEvent = datatable(...) query generated internally by Sentinel to reconstruct the event that triggered the alert?
  3. Is there any Microsoft documentation that describes: the source of the Query property, when it is populated, and in which alert/incident scenarios it is available?
  4. Is it expected that manually created incidents do not contain the Query property and therefore cannot be processed by playbooks that rely on:

@body('Parse_JSON')['Query']

Any clarification or official documentation references would be appreciated.

Thanks!

Microsoft Security | Microsoft Sentinel
0 comments No comments

1 answer

Sort by: Most helpful
  1. AI answer

    2026-11-03T11:19:44.56+00:00

    The playbook should treat Query as an optional, alert-derived property and test for it before calling Run query and list results, because it is not part of the guaranteed Microsoft Sentinel incident or security-alert schema.

    Where Query comes from

    Query is being read from the output of Parse JSON, but Parse JSON does not create that value—it only exposes fields found in its input according to its configured schema.

    For an incident-triggered playbook, the likely input is Alert Custom Details. An incident contains an array of alerts, and each alert can expose custom details as key-value pairs. Their schema depends on the alert and event type. Microsoft’s playbook guidance explicitly has Parse JSON consume Alert Custom Details and generate its schema from a representative alert instance.^1^

    At the storage level, alert custom details and dynamic alert details are placed in the alert’s ExtendedProperties collection.^2^ Therefore, inspect the Parse JSON Content input in the run history and the corresponding alert’s ExtendedProperties to establish the exact propagation path.

    Query is not listed as a standard field in the documented SecurityAlert schema. Microsoft also notes that alerts come from different sources and that not every field is used by every provider.^2^ It should consequently not be treated as guaranteed for:

    • Every scheduled or NRT analytics-rule alert.
    • Alerts ingested from Defender or another provider.
    • Every alert within the same incident.
    • Incidents with no underlying alert carrying that property.

    Scheduled analytics rules do generate alerts from query results, while Microsoft Security analytics rules create incidents from alerts ingested from other products.^2^ That distinction explains why similar incidents can have different extended properties, but the documentation does not establish that every analytics-rule-generated alert receives a field literally named Query.

    Meaning of the generated KQL

    The shown KQL is a reconstruction query:

    let alertedEvent = datatable(compressedRec:string)
    [
        '...base64-encoded zlib payload...'
    ]
    | extend raw = todynamic(
        zlib_decompress_from_base64_string(compressedRec))
    | evaluate bag_unpack(raw)
    | project-away compressedRec;
    alertedEvent
    

    Its operations are:

    1. datatable() creates an inline table containing the compressed string.^3^
    2. zlib_decompress_from_base64_string() decodes Base64 and decompresses the zlib value.^4^
    3. todynamic() converts the resulting serialized object into a dynamic value.
    4. bag_unpack() expands that property bag into columns.^5^
    5. The final statement returns the reconstructed row.

    Functionally, this reconstructs the event data embedded in that alert. However, the available Sentinel documentation does not define this exact compressed KQL representation as a stable public contract. Avoid depending on its internal format beyond submitting the supplied query unchanged.

    Why the manual incident fails

    Yes, the observed failure is expected for this workflow design. A manually created incident can represent activity that was never ingested as Sentinel telemetry and can be created with fields such as title, description, severity, status, owner, and tags.^6^ It does not inherently have:

    • An analytics-rule execution.
    • A query result.
    • An alert containing custom details.
    • A reconstructed triggering event.

    Therefore, the expression below fails when Query is absent:

    @body('Parse_JSON')['Query']
    

    Make the playbook safe for both cases

    Immediately after Parse JSON, add a Condition using null-safe property access:

    @not(empty(body('Parse_JSON')?['Query']))
    

    Then configure the branches:

    1. If true: run Run query and list results with:
         @body('Parse_JSON')?['Query']
      
    2. If false: skip that action and follow a manual-incident path—for example, add a comment explaining that no alert reconstruction query was supplied, or terminate successfully as “Skipped.”

    If the incident can contain multiple alerts, retain the For each loop created around Alert Custom Details and evaluate the condition separately for each alert. Sentinel documents that the incident trigger receives the incident together with its included alerts and entities, while dynamic fields are populated from actual trigger/action output.^7^

    Also update the Parse JSON schema so Query is not listed under required. Otherwise, Parse JSON itself can fail before the condition is evaluated.


    References

    1. Create and manage Microsoft Sentinel playbooks
    2. Microsoft Sentinel security alert schema reference
    3. datatable operator
    4. zlib_decompress_from_base64_string () - Kusto | Microsoft Learn
    5. bag_unpack plugin
    6. Create your own incidents manually in Microsoft Sentinel in the Azure portal
    7. Azure Logic Apps for Microsoft Sentinel playbooks
    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.