Agent Foskett Academy • KQL Academy • Module 14 • Lesson 161 • Detection Engineering & Proactive Threat Hunting

Lesson 161 — The Hunt Started With a Behaviour, Not an IOC

Module 14 changes the question. Until now, many investigations began because something had already happened: an alert fired, a user behaved strangely or telemetry exposed a suspicious event. Proactive threat hunting starts earlier.

There may be no malicious IP address, no known hash and no domain on a blocklist. Instead, the analyst begins with a behaviour that should be uncommon — for example, a browser or Office application launching PowerShell — and asks whether that behaviour exists anywhere in the environment.

An IOC asks, “Have we seen this known bad thing?” A behavioural hunt asks, “Have we seen activity that behaves like the technique we are looking for?”
Agent Foskett KQL Academy behaviour-led proactive threat hunting
Your hunting hypothesis

An attacker may use a trusted user-facing application to launch PowerShell and execute follow-on activity. You do not have a hash, IP address or domain. You have a behaviour to hunt.

✓ Define the behaviour
✓ Measure normal activity
✓ Find unusual parent-child relationships
✓ Combine weak behavioural signals

Hunt briefing

HUNT HYPOTHESIS ATTACK TECHNIQUE Trusted application launches PowerShell ↓ NO KNOWN IOC No malicious hash No confirmed IP No known domain ↓ BEHAVIOURAL QUESTION Where does PowerShell appear, what launches it, and which execution patterns do not fit normal activity? ↓ HUNT Broad telemetry → baseline → unusual behaviour → supporting signals → candidate investigation

Hunting objective

Use Microsoft Defender endpoint telemetry and KQL to turn a behavioural hypothesis into a structured hunt, establish what normal PowerShell execution looks like, isolate unusual parent-child relationships and combine multiple behavioural signals to produce high-value investigation candidates.

Hunter's rule

Do not start by trying to prove your hypothesis. Start by testing it. A good hunt can end with “this behaviour is normal here” and still improve your understanding of the environment.

Stage 1 — begin broad enough to understand the behaviour

Start with PowerShell executions across the environment. Preserve the initiating process and command line so you can see how PowerShell is normally launched.

01-understand-powershell-behaviour.kql
1234567891011
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| project Timestamp,
          DeviceName,
          AccountName,
          FileName,
          ProcessCommandLine,
          InitiatingProcessFileName,
          InitiatingProcessCommandLine
| order by Timestamp desc

Do not filter too aggressively yet

If the first query contains every suspicious keyword you already expect, you risk building a hunt that can only find the attack you imagined. Begin broad enough to learn from the telemetry.

Parent-child relationships matter

powershell.exe is not automatically suspicious. The process that launched it and the command it received can make the same executable either routine administration or a high-value lead.

Stage 2 — establish the environmental baseline

Measure which processes normally launch PowerShell and how widely those relationships occur. This gives the hunt environmental context before you label anything abnormal.

02-baseline-powershell-parent-processes.kql
12345678
DeviceProcessEvents
| where Timestamp > ago(30d)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| summarize Executions=count(),
            Devices=dcount(DeviceName),
            Users=dcount(AccountName)
          by InitiatingProcessFileName
| order by Executions desc

Common is not automatically safe

An attacker can abuse common administrative behaviour. Baseline helps prioritise rarity and deviation; it does not create an allow list of trusted activity.

Rare is not automatically malicious

A legitimate software deployment, support script or administrator may create a parent-child relationship seen only once. Rarity creates a question, not a verdict.

Stage 3 — test the behavioural hypothesis

Now narrow the hunt to user-facing and script-host processes launching PowerShell. These relationships deserve attention because they can appear in phishing, drive-by execution and script-based attack chains.

03-hunt-suspicious-powershell-parents.kql
12345678910111213141516
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| where InitiatingProcessFileName in~ (
    "winword.exe", "excel.exe", "outlook.exe",
    "chrome.exe", "msedge.exe", "firefox.exe",
    "wscript.exe", "cscript.exe", "mshta.exe"
)
| project Timestamp,
          DeviceName,
          AccountName,
          InitiatingProcessFileName,
          FileName,
          ProcessCommandLine,
          SHA1
| order by Timestamp desc

The behaviour is the pivot

Notice that the query does not depend on a known malicious IP or hash. If the attacker changes infrastructure tomorrow, the behavioural relationship may still be visible.

Preserve the hash anyway

Behaviour-led hunting does not mean ignoring IOCs. Once a suspicious process is found, hashes, IP addresses, URLs and domains become valuable pivots for scoping the incident.

Stage 4 — find first-seen relationships

Compare recent parent-child relationships with historical telemetry. A process relationship appearing on a device for the first time can be a useful hunting signal.

04-find-first-seen-process-relationships.kql
123456789101112131415161718192021
let Lookback = 30d;
let Recent = 24h;
let Baseline =
    DeviceProcessEvents
    | where Timestamp between (ago(Lookback) .. ago(Recent))
    | where FileName in~ ("powershell.exe", "pwsh.exe")
    | summarize HistoricalCount=count()
      by DeviceName, InitiatingProcessFileName;
let Current =
    DeviceProcessEvents
    | where Timestamp > ago(Recent)
    | where FileName in~ ("powershell.exe", "pwsh.exe")
    | summarize CurrentCount=count(),
                Commands=make_set(ProcessCommandLine, 20)
      by DeviceName, InitiatingProcessFileName;
Current
| join kind=leftouter Baseline
    on DeviceName, InitiatingProcessFileName
| extend HistoricalCount=coalesce(HistoricalCount, 0)
| where HistoricalCount == 0
| order by CurrentCount desc

First seen needs sufficient history

A relationship may look new because the device was recently onboarded, telemetry was unavailable or retention is limited. Always understand the observation window behind “first seen”.

Environment-wide and device-specific rarity differ

A relationship may be common across the enterprise but completely new for one workstation. Both perspectives can reveal useful anomalies.

Stage 5 — combine weak signals into stronger candidates

One behavioural signal may generate too much noise. Combine suspicious parent processes with encoded commands, download behaviour and hidden execution to rank the events that deserve investigation first.

05-score-behavioural-signals.kql
123456789101112131415161718192021222324252627282930313233343536
DeviceProcessEvents
| where Timestamp > ago(7d)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| extend SuspiciousParent =
    InitiatingProcessFileName in~ (
        "winword.exe", "excel.exe", "outlook.exe",
        "chrome.exe", "msedge.exe", "firefox.exe",
        "wscript.exe", "cscript.exe", "mshta.exe"
    )
| extend EncodedCommand =
    ProcessCommandLine has_any ("-enc", "-encodedcommand")
| extend DownloadBehaviour =
    ProcessCommandLine has_any (
        "Invoke-WebRequest", "iwr ",
        "DownloadString", "WebClient",
        "Start-BitsTransfer"
    )
| extend HiddenExecution =
    ProcessCommandLine has_any (
        "-w hidden", "-windowstyle hidden",
        "-nop", "-noprofile"
    )
| extend BehaviourScore =
    toint(SuspiciousParent) +
    toint(EncodedCommand) +
    toint(DownloadBehaviour) +
    toint(HiddenExecution)
| where BehaviourScore >= 2
| project Timestamp,
          DeviceName,
          AccountName,
          BehaviourScore,
          InitiatingProcessFileName,
          ProcessCommandLine,
          SHA1
| order by BehaviourScore desc, Timestamp desc

A score is prioritisation, not proof

The behavioural score helps order results. It is not a mathematical probability that an event is malicious and should never replace analyst validation.

Good hunts create new questions

A high-value result should trigger pivots into network, file, user and device telemetry. Threat hunting is an iterative investigation process, not a single query.

Agent Foskett's behaviour-led hunt

HYPOTHESIS User-facing applications should rarely launch suspicious PowerShell in this environment ↓ BROAD SEARCH Find PowerShell execution ↓ BASELINE Measure normal parent processes ↓ BEHAVIOURAL FILTER Browser / Office / script host → PowerShell ↓ RARITY Find first-seen relationships ↓ SUPPORTING SIGNALS Encoded command Download behaviour Hidden execution ↓ PRIORITISED CANDIDATES ↓ INVESTIGATION Pivot into process + file + network + identity evidence
The hunt did not begin with something the attacker forgot to change. It began with behaviour the attacker needed to perform.

IOC hunting versus behaviour hunting

ApproachStrengthLimitation
Known malicious hashPrecise and fast to search.Fails when the payload changes.
Known malicious IP or domainExcellent for scoping known infrastructure.Infrastructure can be rotated quickly.
Behavioural relationshipCan survive changes to infrastructure and payload.Often requires baseline and analyst interpretation.
Multiple behavioural signalsCan reduce noise and expose attack patterns.Must be tested to avoid overfitting.
Behaviour + IOC correlationCombines resilient hunting with precise pivots.Still requires validation and context.

Write the hunt finding like an analyst

Example: A proactive behavioural hunt was conducted across Microsoft Defender endpoint process telemetry to identify unusual PowerShell execution without relying on a known malicious indicator. PowerShell parent-process relationships were baselined across the environment before focusing on execution initiated by browsers, Office applications and script hosts. Candidate events were further prioritised using first-seen relationships and supporting command-line behaviours including encoded commands, download functionality and hidden execution. The resulting events represent investigation candidates rather than confirmed compromise. Each candidate should be validated against expected administrative and application behaviour and correlated with file, network, user and device telemetry before escalation.

Lesson 161 key takeaways

  • Proactive hunting can begin with a behaviour rather than a known IOC.
  • Write a hunting hypothesis that can be tested rather than a conclusion you intend to prove.
  • Start broad enough to understand how the behaviour normally appears.
  • Baseline parent-child process relationships before labelling them unusual.
  • Common behaviour is not automatically benign and rare behaviour is not automatically malicious.
  • Behavioural hunts can remain useful when attackers change hashes or infrastructure.
  • First-seen relationships can provide valuable anomaly context.
  • Observation windows and telemetry coverage affect rarity conclusions.
  • Combine multiple weak signals to prioritise investigation candidates.
  • A hunting score ranks evidence; it does not prove compromise.

Module 14 has begun

Lesson 161 introduced the behaviour-led hunting mindset. Next we take a useful behavioural query and discover that the same technique appears on multiple devices — forcing us to move from a single hunting result into environment-wide scoping.

Next: Lesson 162 — One Query Found the Same Technique on Twelve Devices.

Continue your KQL investigation training

Module 14 moves from reactive investigation into proactive threat hunting and detection engineering.

🔎 KQL Academy — Module 14: Advanced Detection Engineering & Proactive Threat Hunting

Turn investigation knowledge into proactive hunts, reusable analytics and higher-confidence detections.
⬅ Previous lesson
Lesson 160 — Building the Complete Cloud Compromise TimelineComplete the Module 13 cloud compromise investigation.
✅ Current lesson
Lesson 161 — The Hunt Started With a Behaviour, Not an IOCBuild a proactive hunt from suspicious behaviour rather than a known indicator.
Next lesson
Lesson 162 — One Query Found the Same Technique on Twelve DevicesScope a behavioural hunting result across the environment and determine whether repeated activity represents legitimate tooling or a wider attack.

Learn behaviour-led threat hunting with KQL

Lesson 161 of the Agent Foskett KQL Academy begins Module 14 by showing how to hunt proactively across Microsoft Defender endpoint telemetry without relying on a known malicious hash, IP address or domain.

Build proactive KQL hunts from attacker behaviour

Learn how to define a hunting hypothesis, baseline PowerShell execution, identify unusual process relationships, find first-seen behaviour and combine multiple weak signals into high-value investigation candidates.