Skip to content

NQL Syntax Cheat Sheet

Note

Ultra-quick reference for writing NQL queries - print this or keep it open while querying!

Basic Query Structure

<table> during past <time> | where <filter> | compute <calc> | summarize <agg> | list <fields> | sort <field> asc/desc | limit <n>

Clause Order (Memorize This!)

1. where          (filter early!)
2. with/include   (join events)
3. compute        (per-object calc)
4. summarize      (aggregate)
5. list           (select fields)
6. sort           (order results)
7. limit          (restrict rows)

Comments

/* This is a comment */
/* Multi-line comments
   are supported */

/* ⚠️ Comments do NOT work within clauses */
/* ✅ CORRECT - Comment between clauses */
devices
/* Filter to Windows devices */
| where operating_system.platform == windows
| list device.name

/* ❌ WRONG - Comment within clause (will error!) */
| where /* filter */ operating_system.platform == windows

Time Windows

during past 1d    # 1 day (low-resolution, cloud timezone)
during past 7d    # 7 days (daily aggregation)
during past 24h   # 24 hours (high-resolution, user timezone)
during past 48h   # 48 hours (5-15 min samples)

⚠️ past 2d ≠ past 48h (different resolution & timezone!)

Essential Keywords

Keyword Purpose Example
list Select fields to display list device.name, memory
where Filter rows where os.name = "Windows 11"
with Join - objects WITH events only with execution.crashes
include Join - ALL objects (even without events) include execution.events
compute Calculate per object (after with/include) compute avg = memory.avg()
summarize Aggregate to single result or groups summarize total = count()
by Group by dimension or time by device.name or by 1d
sort Order results sort memory desc
limit Restrict number of rows limit 20

Common Aggregation Functions

count()              # Count events (avoid on sampled events!)
device.count()       # Count unique devices (use this!)
user.count()         # Count unique users
application.count()  # Count unique applications
field.sum()          # Total
field.avg()          # Average (use this for computed averages!)
field.max()          # Maximum
field.min()          # Minimum
field.last()         # Most recent value

Wildcards in Filters

where name = "Microsoft*"        # Starts with Microsoft
where name = "*Office*"          # Contains Office
where name = "*.exe"             # Ends with .exe
where os.name = "Windows 1?"     # Single char wildcard (10, 11)

Operators

==  or  =    # Equals (both work)
!=           # Not equals
>            # Greater than (numbers, dates, durations)
<            # Less than
>=           # Greater or equal
<=           # Less or equal
in [ ]       # In list: where name in ["chrome.exe", "firefox.exe"]
and          # Logical AND
or           # Logical OR
not          # Logical NOT

Output Formatting (as function)

value.as(format = percent)                # 0.47 → 47%
value.as(format = currency, code = USD)   # 2000 → $2,000
value.as(format = bytes)                  # 1073741824 → 1 GB
value.as(format = bitrate)                # 1500000 → 1.5 Mbps
value.as(format = energy)                 # 1500 → 1.5 kWh

Critical Syntax Rules (Avoid These Errors!)

/* ❌ compute after summarize */
summarize total = sum() | compute percent = total / 100  # ERROR!
/* ✅ summarize percent = sum() / 100  # Correct */

/* ❌ Reference variables within same summarize */
summarize a = sum(), b = a / 100  # ERROR!
/* ✅ summarize a = sum(), b = sum() / 100  # Correct - repeat calculation */

/* ❌ count() on sampled events */
execution.events | summarize total = count()  # Returns sample count!
/* ✅ execution.events | summarize total = device.count()  # Useful! */

/* ❌ Missing time window on events */
execution.events | summarize count = count()  # ERROR!
/* ✅ execution.events during past 7d | summarize count = count()  # Correct */

/* ❌ Exceeding retention limits */
execution.events during past 15d  # May fail (8-day high-res limit)!
/* ✅ execution.events during past 7d  # Within limits */

Common Tables

devices                      # Device inventory (no time needed)
execution.events             # Process execution (8d high-res, 30d low-res)
execution.crashes            # Application crashes
device_performance.events    # CPU, memory, disk metrics
connection.events            # Network connections (8d high-res, 30d low-res)
web.events                   # Web browsing

Quick Syntax Check Before Running

□ Event table has "during past Xd" or "during past Xh"
□ Filters use correct operators (= for strings, > for numbers)
□ No compute after summarize
□ No variable references within same summarize
□ Field names match table (check Field Reference if unsure)
□ Using device.count() not count() on sampled events
□ Added | limit 10 for testing

Typical Query Patterns (Copy & Modify)

Pattern 1: Top N Devices by Metric

/* Find top 20 devices by metric */
execution.events during past 7d
| where binary.name = "PROCESS.exe"
| summarize metric = field.avg() by device.name
| list device.name, metric
| sort metric desc
| limit 20

Pattern 2: Trend Over Time

/* Hourly trend analysis */
execution.events during past 7d
| where binary.name = "PROCESS.exe"
| summarize metric = field.avg() by 1h
| sort start_time asc

Pattern 3: All Devices with Computed Metric

/* Complete device inventory with metrics */
devices
| include execution.events during past 7d
| compute metric = field.sum()
| list device.name, metric
| sort metric desc

Pattern 4: Filter and Count

devices
| with execution.crashes during past 7d
| where binary.name = "app.exe"
| summarize crash_count = count()

Pattern 5: Percentage Calculation

devices
| include execution.crashes during past 7d
| compute has_crash = count()
| summarize
    total_devices = count(),
    devices_with_crashes = has_crash.countif(has_crash > 0),
    crash_percentage = (has_crash.countif(has_crash > 0) * 100.0) / count()

with vs include Quick Reference

/* with - Only objects WITH events (filters) */
devices
| with execution.crashes during past 7d
| list device.name
/* Returns: 15 devices (only those with crashes) */

/* include - ALL objects with metrics (computes) */
devices
| include execution.crashes during past 7d
| compute crash_count = count()
| list device.name, crash_count
/* Returns: 142 devices (all devices, crash_count = 0 for some) */

Rule: - Use with to filter (only objects with events) - Use include to compute metrics (all objects, including 0)

Common Field Patterns

Device Fields

device.name
device.operating_system.name
device.hardware.memory
device.volumes.size
device.department

Event Context Fields (Historical)

context.os_name                    # OS at event time
context.device_platform
context.hardware_model
context.department

execution.events Fields

binary.name                        # Process name
binary.real_binary.version
cpu_time                           # CPU usage
real_memory                        # Memory consumption
execution_duration
startup_duration

connection.events Fields

event.destination.domain
event.number_of_connections
event.failed_connection_ratio
incoming_traffic
outgoing_traffic
connection_establishment_time      # RTT

Data Retention Quick Reference

Table High-Res (past Xh) Low-Res (past Xd)
execution.events 8 days 30 days
connection.events 8 days 30 days
Other event tables 30 days 30 days
devices N/A (no time needed) N/A

Pro Tips

Always add | limit 10 during query development, remove when finalized!

Filter early with where - massive performance gains!

Use past Xd for trends/reports, past Xh for troubleshooting!

Test incrementally: base table → filter → aggregation → calculations

When in doubt, check Field Reference for valid fields



Print this page or bookmark it for quick reference while writing queries!