Microsoft Sentinel is one of the fastest-growing SIEMs in enterprise security right now and for good reason. The KQL query language is powerful, the integration with the Microsoft security stack is tight, and the threat hunting capabilities are genuinely strong when you know how to use them.
The problem is that most KQL content online is either basic tutorial material or vendor documentation that doesn't reflect how real analysts actually hunt. These queries come from production environments at major financial institutions. Every one has been tuned against real alert volume and real false positive patterns.
All queries use the DeviceProcessEvents, SigninLogs, DeviceNetworkEvents, and SecurityEvent tables. Default time range 30 days. Tune exclusion lists to your environment before alerting. Always baseline against 30 days of historical data before converting any query to a detection rule.
Get a new KQL, LogScale, or SPL query like these every Tuesday, with the tuning notes already done.
Join — $14.99/moQuery 1: Suspicious PowerShell Execution from Office Applications
This is one of the highest-confidence detection queries in a Sentinel environment. Office applications spawning PowerShell is almost never legitimate in an enterprise setting. When it happens, it is almost always post-phishing execution.
DeviceProcessEvents
| where Timestamp > ago(30d)
| where FileName =~ "powershell.exe" or FileName =~ "pwsh.exe"
| where InitiatingProcessFileName in~ (
"WINWORD.EXE", "EXCEL.EXE", "OUTLOOK.EXE",
"MSPUB.EXE", "MSACCESS.EXE", "chrome.exe",
"msedge.exe", "firefox.exe"
)
| where isnotempty(ProcessCommandLine)
| project Timestamp, DeviceName, AccountName,
ProcessCommandLine, InitiatingProcessFileName
| order by Timestamp desc
What to flag immediately
- -EncodedCommand in the command line combined with an Office parent process is an immediate P1 escalation
- IEX or Invoke-Expression suggests in-memory execution, no file dropped to disk
- DownloadString or WebClient means the payload is being pulled from an external source
- Bypass -ExecutionPolicy confirms the attacker is deliberately circumventing controls
Query 2: New Local Administrator Account Creation
Attackers who establish a foothold frequently create new local administrator accounts as a persistence mechanism. This query surfaces account creation events specifically targeting the Administrators group, filtered to focus on unusual timing.
SecurityEvent
| where TimeGenerated > ago(30d)
| where EventID == 4720 or EventID == 4732
| where TargetUserName !endswith "$"
| extend Hour = hourofday(TimeGenerated)
| where Hour < 7 or Hour > 19
| project TimeGenerated, Computer, SubjectUserName,
TargetUserName, EventID,
Activity = iff(EventID == 4720,
"Account Created", "Added to Group")
| order by TimeGenerated desc
Investigation steps when this fires
- Check SubjectUserName against your known admin accounts. Service accounts creating new accounts is a major red flag.
- Verify the naming convention matches your organisation's standard format. Attackers rarely know internal naming patterns.
- Pull the creating account's full activity for the previous 48 hours looking for other anomalies.
- Check whether the new account was immediately added to Domain Admins or other privileged groups.
Query 3: Impossible Travel Detection
Credential theft followed by remote access from a different country is one of the most reliable signals of account compromise. This query finds successful authentications from different countries within a time window that makes physical travel impossible.
let timeWindow = 2h;
SigninLogs
| where TimeGenerated > ago(30d)
| where ResultType == 0
| where isnotempty(Location)
| summarize
Countries = make_set(Location),
IPs = make_set(IPAddress),
SigninTimes = make_list(TimeGenerated)
by UserPrincipalName, bin(TimeGenerated, timeWindow)
| where array_length(Countries) > 1
| project TimeGenerated, UserPrincipalName,
Countries, IPs, SigninTimes
| order by TimeGenerated desc
Adjust the timeWindow variable based on your environment. Two hours is aggressive and will generate false positives for VPN users. Four to six hours is more practical for most enterprise environments while still catching real impossible travel scenarios.
Query 4: Scheduled Task Creation Outside Business Hours
Scheduled tasks are one of the most common persistence mechanisms because they survive reboots and are often overlooked during IR. This query surfaces new scheduled task creation during off-hours, specifically targeting tasks that execute scripts or executables from user-writable paths.
DeviceProcessEvents
| where Timestamp > ago(30d)
| where FileName =~ "schtasks.exe"
| where ProcessCommandLine has "/create"
| where ProcessCommandLine has_any (
"powershell", "cmd", "wscript",
"cscript", "mshta", "AppData", "Temp"
)
| extend Hour = hourofday(Timestamp)
| where Hour < 7 or Hour > 19
| project Timestamp, DeviceName, AccountName,
ProcessCommandLine, InitiatingProcessFileName
| order by Timestamp desc
High confidence indicators in the results
- Task executing from AppData, Temp, or Downloads paths is almost always malicious
- Task created by a standard user account rather than a service account or admin
- Task name that mimics legitimate Windows tasks but with slight spelling variations
- Task trigger set to run at logon or at system startup for maximum persistence
Query 5: Large Volume File Access by Single Account
Data exfiltration before ransomware deployment and insider threat scenarios both generate unusual file access volume patterns. This query baselines normal file access and surfaces accounts that significantly exceed their typical activity.
let baseline = DeviceFileEvents
| where Timestamp between (ago(30d) .. ago(1d))
| where ActionType in ("FileRead", "FileAccessed")
| summarize BaselineAvg = avg(count()),
BaselineStd = stdev(count())
by DeviceName, AccountName, bin(Timestamp, 1d);
DeviceFileEvents
| where Timestamp > ago(1d)
| where ActionType in ("FileRead", "FileAccessed")
| summarize TodayCount = count()
by DeviceName, AccountName
| join kind=inner baseline
on DeviceName, AccountName
| where TodayCount > BaselineAvg + (3 * BaselineStd)
| project DeviceName, AccountName,
TodayCount, BaselineAvg,
Deviation = TodayCount - BaselineAvg
| order by Deviation desc
Query 6: MFA Bypass via Legacy Authentication Protocols
Legacy authentication protocols like SMTP, IMAP, and POP3 do not support modern authentication and therefore bypass MFA entirely. Attackers with stolen credentials specifically target these protocols because they circumvent your MFA controls completely.
SigninLogs
| where TimeGenerated > ago(30d)
| where ResultType == 0
| where ClientAppUsed in (
"Exchange ActiveSync", "IMAP4", "MAPI",
"POP3", "SMTP", "Other clients"
)
| where AuthenticationRequirement != "multiFactorAuthentication"
| project TimeGenerated, UserPrincipalName,
IPAddress, Location, ClientAppUsed,
AppDisplayName, DeviceDetail
| order by TimeGenerated desc
What to do when this fires
- Confirm whether legacy authentication is disabled in your Conditional Access policies. If it is and this query still returns results, you have a policy gap.
- Check the authenticating IP against your known IP ranges. External IPs using legacy auth with valid credentials is a strong compromise indicator.
- Pull the full signin history for any flagged account across all auth methods for the previous 30 days.
Production detection rule, real incident case study, hunt hypothesis with query, and a career tip, every Tuesday. Plus monthly Office Hours, private Discord, and a growing detection archive. First 25 subscribers lock in $14.99/month for life.
Join Intelligence Pack — $14.99/month SOC Starter Kit — $39Cancel anytime. 30-day money back guarantee.