A cloud-native SIEM solution that provides intelligent security analytics and threat detection across systems
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:
-
datatable()creates an inline table containing the compressed string.^3^ -
zlib_decompress_from_base64_string()decodes Base64 and decompresses the zlib value.^4^ -
todynamic()converts the resulting serialized object into a dynamic value. -
bag_unpack()expands that property bag into columns.^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:
- If true: run Run query and list results with:
@body('Parse_JSON')?['Query'] - 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
- Create and manage Microsoft Sentinel playbooks
- Microsoft Sentinel security alert schema reference
- datatable operator
- zlib_decompress_from_base64_string () - Kusto | Microsoft Learn
- bag_unpack plugin
- Create your own incidents manually in Microsoft Sentinel in the Azure portal
- Azure Logic Apps for Microsoft Sentinel playbooks