Microsoft Sentinel KQL: An Introduction for Threat Hunting

Share

Introduction to Microsoft Sentinel KQL

Most organizations run “reactive” detection: an alert fires, you investigate, you remediate. Threat hunting changes the logic: you form hypotheses, explore data, and look for weak signals at scale, at a time when attackers automate everything.

Microsoft Sentinel is particularly well suited to this work, as long as you have a basic command of KQL (Kusto Query Language). The goal of this article isn’t to drown you in syntax: it’s to give you a method, key commands, and “reusable” queries to hunt effectively through logs.

What you’ll learn in this guide

  • Understand the role of threat hunting in Sentinel
  • Know where to look: tables, time ranges, and useful fields
  • Master essential KQL commands (search, where, project, summarize, join, parse, mv-expand)
  • Build hunting queries to spot advanced behaviors
  • Analyze and interpret results to move into the “investigation” phase

Threat hunting vs detection vs investigation (in 30 seconds)

  • Detection: rules/analytics based on known events (alerts).
  • Investigation: you follow an alert and reconstruct an event chain.
  • Threat hunting: you start from a hypothesis (e.g., “quiet lateral movement”) and explore data to find traces.

Prerequisites (so hunting is actually useful)

Before writing queries, make sure you have:

  • Connectors enabled (Microsoft 365, Azure, Defender, Windows, etc.)
  • Consistent retention (otherwise you hunt over 7 days and miss the signal)
  • A naming and tagging convention (workspaces, tables, VIP accounts)
  • A clear objective: “reduce time to detect,” “detect exfiltration,” etc.

SC-200 module to expand (what we’ll cover)

The module “Create queries for Microsoft Sentinel using KQL” aims to:

  • Build KQL statements for Microsoft Sentinel
  • Analyze query results
  • Generate multi-table queries
  • Use Sentinel data through KQL
In this article, we take those objectives and apply them with a field-oriented, hunting-first approach.

1) Where to hunt: understanding tables and the “datastore”

In Sentinel, your data is stored in Log Analytics as tables. Each connector feeds one or more tables.

How to discover available tables

Start by exploring your data ecosystem:

  1. Global search:
  • search "keyword"
  1. Quick time filter:
  • | where TimeGenerated > ago(24h)
  1. Project only the fields you need:
  • | project TimeGenerated, Computer, Account, IPAddress, OperationName
Tip: avoid hunting without a time constraint. Start with 1 hour, then 24 hours, then 7 days.

2) Essential KQL commands (the hunter’s “kit”)

These are the commands you’ll use 80% of the time.
 
where (filter)
  • | where Account contains "admin"
  • | where IPAddress startswith "10."

project (select columns)

  • | project TimeGenerated, Account, IPAddress, ActionType

extend (create a field)

  • | extend Hour = datetime_part("hour", TimeGenerated)

summarize (aggregate)

  • | summarize count() by Account
  • | summarize dcount(IPAddress) by Account

order by and take

  • | order by TimeGenerated desc
  • | take 50

join (correlate)

  • | join kind=inner (...) on DeviceId

parse / extract (extract)

  • Useful for semi-structured fields.

mv-expand (expand arrays)

  • Useful when a field contains a list (e.g., IPs, URLs).

3) “Hunting” query patterns (ready to copy)

The examples below are patterns. Adapt the tables based on your connectors (Defender, Azure AD/Entra, M365, etc.).

A) Detect abnormal authentication (impossible travel / unexpected country)

SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0
| summarize Countries = make_set(LocationDetails.countryOrRegion) by UserPrincipalName
| where array_length(Countries) > 1

B) Count MFA / sign-in failures (noise vs signal)

SigninLogs
| where TimeGenerated > ago(24h)
| summarize Failures = countif(ResultType != 0), Success = countif(ResultType == 0) by UserPrincipalName
| where Failures > 10 and Success > 0
| order by Failures desc

C) Broad search (when you only have one clue)

search "rundll32"
| where TimeGenerated > ago(7d)
| take 200

D) Spot suspicious PowerShell executions (example)

DeviceProcessEvents
| where TimeGenerated > ago(24h)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| where ProcessCommandLine has_any ("-enc", "IEX", "DownloadString", "FromBase64String")
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine
| order by TimeGenerated desc

E) Correlate a user + a device (join)

let suspiciousUsers = SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0
| summarize by UserPrincipalName;

DeviceLogonEvents
| where TimeGenerated > ago(24h)
| join kind=inner suspiciousUsers on $left.AccountUpn == $right.UserPrincipalName
| project TimeGenerated, DeviceName, AccountUpn, LogonType

4) How to analyze results (without fooling yourself)

Avoid classic false positives:

  • Service accounts and automation accounts
  • VPN/proxy hops (same user, different IP)
  • Internal scans (security tools)

Move from “list” to “story”:

A good hunting result should let you tell:

  • Who? (account)
  • What? (action)
  • Where? (device, IP, country)
  • When? (timeline)
  • What next? (potential impact)

External links (useful references)

Your next steps

  1. Pick onr hunting hypothesis (e.g., encoded PowerShell execution).
  2. Run the query over 24 hours, then 7 days.
  3. Add one correlation (join) to enrich context.
  4. Turn your query into a reusable rule / workbook / hunting query.

Recommended certification & training paths (practical options)

  • Microsoft Security Operations Analyst: SC-200 (Sentinel, Defender, investigation)
  • Security fundamentals: SC-900 (if you’re starting out)
  • Sentinel specialization: SC-5001 (intermediate to advanced)

FAQ

No. KQL is designed for log analysis. With just a few commands (where, project, summarize), you can already produce useful results.

A hunting query is exploratory (hypothesis, research). An analysis rule automatically generates alerts.

Start with the tables linked to your main connectors (SigninLogs, AuditLogs, DeviceProcessEvents, DeviceNetworkEvents, etc.).

Create exception lists (service accounts, VPN IPs), add context (join), and use thresholds (summarize) adapted to your environment.

Explore more articles

Our website uses cookies to personalize your browsing experience. By clicking ‘I accept,’ you consent to the use of cookies.