Skip to main content

From KQL

Synopsis

Azure Sentinel ships its normalization logic as ASIM parsers — a KQL function, wrapped in a YAML file that carries it under a ParserQuery or Query field. Conversion reads that export, or a raw KQL reduction query of the form SourceTable | where ... | extend ... | project ..., and returns a native DataStream pipeline.

You can supply either the full ASIM parser YAML export, in which case the query and the parser name are extracted automatically, or the KQL text on its own.

Do not hand-translate a KQL query. Drive the conversion through an AI coding agent connected to the hosted MCP server, as described in Testing.

DataStream uses KQL in two unrelated ways, and it is worth being precise about which one this page describes.

Federated Search runs KQL as a query language. You write a query, and DataStream executes it against your data at query time.

Conversion, described here, treats KQL as a source format. The query is translated once, at import, into a DataStream pipeline — and then it is gone. Nothing about KQL survives into pipeline execution; the result is ordinary YAML that runs like any other pipeline.

The two are complementary rather than overlapping. The operators conversion cannot express — summarize, join, sort, and the rest of the aggregation family — are precisely the ones Federated Search exists to run, because they describe work across a set of events rather than work on a single event.

What Converts

Pipe Operators

KQL operatorDataStream processorNotes
whereDropThe condition is negated: events that fail it are dropped. An ASIM where not(disabled) guard is recognized and skipped.
extendVariesEach assignment is lowered by its value expression. See Scalar Functions.
projectKeepComputed columns are emitted first, then the field list is kept.
project-keepKeep
project-awayRemoveA suffix wildcard that matches no known field is kept verbatim, with a warning.
project-renameRename
project-reorderNoneA no-op, with a warning. Field order is not significant in a per-event pipeline.
parseDissect or GrokDissect for a pure delimiter pattern, Grok when the captures are typed.
parse-kvKV
lookupLookupEach referenced datatable is registered as inline lookup_content. An unreferenced datatable is pruned.
unionGroupEach branch becomes a group with its own condition. See the limitations below — the tail semantics differ from KQL.
invokeVariesSee ASIM Helpers.

Scalar Functions

KQL functionDataStream processor
Literals, bare field references, strcat, strcat_delim, concat, column_ifexistsSet
coalesceCoalesce
case, iif, iffCase
Arithmetic (+, -, *, /, %)Math
tostring, toint, tolong, todouble, toreal, todecimal, tobool, toboolean, todatetime, and the int(), long(), real(), double() literal castsConvert
unixtime_seconds_todatetime, unixtime_milliseconds_todatetimeDate
toupperUppercase
tolowerLowercase
trim, trim_start, trim_endTrim
replace_string, replace_regexGsub
extractGrok
splitSplit
strcat_arrayJoin
array_sliceSlice
Array indexing, such as arr[0]Select
substringSubstring
todynamic, toobject, parse_jsonJSON
bag_pack, pack, pack_dictionaryBag Pack
base64_encode_tostring, encode_base64, base64_encodestringBase64 Encode
base64_decode_tostring, decode_base64, base64_decodestringBase64 Decode
parse_url, parse_urlqueryURI Parts
url_decodeURL Decode
parse_ipv4, parse_ipv6, ipv4_is_privateIP Type
hash_sha256, hash_md5, hash_sha1Fingerprint
parse_user_agent, user_agentUser Agent
The totimespan(F)/time(1s) duration-ratio idiomDuration

Any other function becomes a Comment carrying the original KQL expression, with a warning.

ASIM Helpers

KQL constructDataStream processor
invoke _ASIM_ResolveNetworkProtocol(...)Network Protocol
invoke _ASIM_ResolveDvcFQDN(...) and its Src, Dst, and Target variantsFQDN
_ASIM_GetUsernameType(...)Username Type

A KQL function defined in the query and then invoked — the ASIM ItemParser idiom — is inlined directly into the pipeline. Any other invoked helper becomes a comment, with a warning.

A literal EventSchema assignment is recognized: the converter prepends a Set writing the corresponding ASIM table name to _vmetric.table.

Conditions

Conditions become DataStream's native if expression language.

KQLNative if
and, or&&, ||
==, !=, <, <=, >, >=Unchanged
contains, contains_cs, icontainscontains()
startswith, hasprefix (and their _cs forms)startsWith()
endswith, hassuffix (and their _cs forms)endsWith()
matchesregexmatches()
in, !inMembership test
isempty, isnotempty, isnull, isnotnull, not()Equivalent native forms
=~, !~A case-insensitive comparison, exactly equivalent
has, has_cs, has_any, has_all and their negationsmatches() against a word-boundary regex — an approximation. See the limitations below.

What Does Not Convert

These operators describe work across a set of events. A DataStream pipeline processes one event at a time, so they have no per-event form:

summarize, distinct, join, sort, order, top, take, limit, mv-expand, mv-apply

They do not abort the conversion. Each one becomes a Comment carrying the original KQL, a warning is added to the pipeline's description, and the remaining stages still convert. What you get back is a partial pipeline that you finish by hand — not an error.

For work that genuinely needs aggregation or joins across events, use Federated Search, which runs KQL as a query rather than converting it.

Known Limitations

A successful conversion can be silently incomplete. The KQL parser recovers from syntax it cannot handle rather than failing outright, so an unparseable construct yields a partial pipeline plus a warning — not an error. Always read the warnings in the converted pipeline's description before trusting the result.

union tail semantics differ. Events that match no union branch continue into the shared tail processors, whereas KQL's union would omit them. The converter emits a warning where this applies.

Hash values change. hash_sha256, hash_md5, and hash_sha1 become a Fingerprint, which produces a deterministic digest — but not the same value KQL produces. Do not rely on migrated hashes matching historical ones.

IP parsing is approximated. parse_ipv4, parse_ipv6, and ipv4_is_private become an IP Type, which is close but not identical.

The has family is approximated. It lowers to a case-insensitive word-boundary regex. KQL's exact term tokenization is not reproduced.

Watchlist-backed let bindings cannot be converted. An expression referencing one is skipped entirely, with a warning.

Detection rules are out of scope. This converter is for normalization parsers and reduction queries. A Sentinel analytics rule is not converted into a pipeline — it is registered, unchanged, with the Smart Engine processor, which uses it to decide what to forward to the SIEM.

Examples

A Reduction Query

A KQL query filtering, computing a field, and narrowing the output columns...

NetworkSession
| where SrcIpAddr != ""
| extend EventVendor = "Fortinet"
| project TimeGenerated, SrcIpAddr, EventVendor

where becomes a negated drop, extend becomes a set, and project becomes a keep...

- drop:
if: "!(SrcIpAddr != '')"
- set:
field: EventVendor
value: Fortinet
- keep:
fields:
- TimeGenerated
- SrcIpAddr
- EventVendor

An ASIM Helper

An ASIM parser resolving a network protocol through the standard helper...

| invoke _ASIM_ResolveNetworkProtocol('NetworkProtocol')

The helper has a native equivalent, so it converts directly...

- network_protocol:
field: NetworkProtocol

An Aggregation

A summarize, which has no per-event equivalent...

| summarize count() by SrcIpAddr

The conversion continues. The operator is preserved as a comment carrying the original KQL, and a warning names it in the pipeline description...

description: |
Converted from KQL (source table: NetworkSession).
Warning [summarize]: KQL stage skipped (could not be converted to a
native processor — manual migration required): operator "summarize"
dropped — not representable per-event; use the KQL->SQL
federated-search path
processors:
- comment:
message: >-
unconverted KQL stage (manual migration required):
|summarizecount()bySrcIpAddr