Using Regular Expressions regex in KQL.
The filename did not look suspicious.
Neither did the command line.
But one pattern appeared across hundreds of events.
Agent Foskett was not looking for one exact value. He was looking for a pattern.
Lesson overview
Learn how to use regular expressions in KQL to match suspicious patterns, extract useful values and hunt across Microsoft Defender XDR telemetry when exact text searches are not enough.
Why regex matters in KQL
The regex investigation workflow
Step 1 — Match suspicious PowerShell command patterns
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName =~ "powershell.exe"
| where ProcessCommandLine matches regex @"(?i)(-enc|-encodedcommand|downloadstring|invoke-webrequest|iex)"
| project Timestamp,
DeviceName,
AccountName,
FileName,
ProcessCommandLine
| order by Timestamp descStep 2 — Detect random-looking executable names
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
DeviceFileEvents
| where Timestamp > ago(7d)
| where FileName matches regex @"(?i)^[a-z0-9]{10,}\.(exe|dll|scr)$"
| project Timestamp,
DeviceName,
FolderPath,
FileName,
InitiatingProcessFileName
| order by Timestamp descStep 3 — Extract domains from suspicious URLs
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
UrlClickEvents
| where Timestamp > ago(7d)
| where isnotempty(Url)
| extend ExtractedDomain = extract(@"https?://([^/]+)", 1, Url)
| project Timestamp,
AccountUpn,
Url,
ExtractedDomain,
ActionType
| order by Timestamp descStep 4 — Hunt suspicious email subjects
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
EmailEvents
| where Timestamp > ago(7d)
| where Subject matches regex @"(?i)(invoice|payment|remittance|overdue).*(urgent|today|immediate)"
| project Timestamp,
RecipientEmailAddress,
SenderFromAddress,
Subject,
DeliveryAction
| order by Timestamp descStep 5 — Extract encoded command values
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine has_any ("-enc", "-encodedcommand")
| extend EncodedValue = extract(@"(?i)-(enc|encodedcommand)\s+([A-Za-z0-9+/=]{20,})", 2, ProcessCommandLine)
| where isnotempty(EncodedValue)
| project Timestamp,
DeviceName,
AccountName,
EncodedValue,
ProcessCommandLineStep 6 — Clean strings with replace_regex()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName =~ "powershell.exe"
| extend NormalisedCommand = replace_regex(ProcessCommandLine, @"(?i)C:\\Users\\[^\\]+", @"C:\Users\USER")
| project Timestamp,
DeviceName,
AccountName,
ProcessCommandLine,
NormalisedCommand
| order by Timestamp descRegex patterns defenders should recognise
Real-world investigation
Investigation checklist
Related Agent Foskett Academy lessons
Coming next
Final thought
Using Regular Expressions regex in KQL
Agent Foskett Academy Lesson 99 teaches defenders how to use regular expressions and regex in KQL to match suspicious patterns across Microsoft Defender XDR telemetry.
Learn regex for Microsoft Defender XDR threat hunting
Regular expressions help Microsoft security analysts identify suspicious command lines, URLs, filenames, email subjects and encoded values when exact string matching is not enough.
KQL regex tutorial for Microsoft security analysts
This lesson explains matches regex, extract(), replace_regex() and practical Defender XDR investigation patterns for endpoint, email and URL telemetry.
