In this section

0.1 What Purple Teaming Is

Module 0

Introduction

The attacker leads, even in the first lesson. A purple team runs an attacker's procedure on purpose, in the open, and then measures what the defense did with every step of it.

This course teaches it from both seats at once: the operator who runs the procedure and the defender who reads what it left, working one exercise with one record. A test is not finished when the procedure runs, or when a rule fires, but when both seats agree what happened at every step, all the way to the analyst's verdict.

This lesson shows what that means on a single recorded test. PT-0103 created a scheduled task from the command line on Tuesday 15 September, the engagement's first day. The rule meant for it alerted six minutes later, and nobody opened an incident. Every later module of the course is a larger version of reading that one test properly.

The course is written for defenders: SOC analysts, detection engineers and incident responders who want to know whether their detections work, and for the people who run the tests that tell them. It assumes you can read a query and know what an alert is. It does not assume you have run an attack before; the operator's seat is taught from the first module.

Each lesson in this module works the same way. It starts from something the operator did, follows the defender through the records it left, and ends with a case you work yourself in the course's console, where every query runs against the recording. The queries are short and the results are small on purpose: the point of Module 0 is the way of reading, not the volume of data.

1

Plan the round

What a purple team test commits each seat to

Every test in this course starts from the same short agreement between the seats, written before anything runs:

A test, agreed by both seats
The operatorRuns one procedure, as written, and records it
The defenderReads what the defense did with each step
TogetherOne record, both seats' rows side by side
FinishedWhen both agree the outcome, to the verdict
Decided byWhether the outcome could be shown from a record, not asserted
Either wayThe result is written down, silent or not

The decision line is the course's habit in one sentence. A purple team that says "we tested scheduled tasks and they are covered" has asserted something; one that says "PT-0103 left four records, PU-R02 alerted at 09:46, and no incident was opened" has shown it, with three queries anyone can rerun. Every lesson trains the second way of speaking.

The agreement is written before the test, not after, because the outcome is easier to read honestly when both seats committed to what they would look for. An operator who decides afterward which records count, or a defender who decides afterward which alerts were meant for the test, can make almost any result look like a pass. Writing the agreement first takes a minute and removes the temptation.

The last line matters as much. A test that raises no alert is a result, and often the most useful one, because it is the gap the exercise exists to find. A purple team that only reports the tests that alerted is reporting the defense's successes and hiding its failures from itself.

2

The attack: an Atomic test, run by its GUID

T1053.005 test 2, a scheduled task created from the command prompt

Every test in this course starts in the operator's seat, with a procedure and the tool that runs it. The first is Atomic Red Team's T1053.005 test 2, Scheduled task Local, GUID 42f53695-ad4a-4546-abb6-7d837f644a71.

Atomic Red Team publishes small, documented procedures for ATT&CK techniques, each a YAML entry with a command, its inputs and its cleanup, so a test run today can be run again next month as exactly the same procedure. This one's executor is the command prompt:

SCHTASKS /Create /SC ONCE /TN spawn /TR #{task_command} /ST #{time}

It creates a task called spawn that would start cmd.exe once, at 20:10, which is the persistence an intruder wants: something Windows will run later on their behalf. Its cleanup deletes the task:

SCHTASKS /Delete /TN spawn /F >nul 2>&1

The operator runs it with Invoke-AtomicTest, the library's PowerShell runner: read it first, check what it needs, run it with the execution log on, and clean up.

PS C:\> $g = '42f53695-ad4a-4546-abb6-7d837f644a71'
PS C:\> Invoke-AtomicTest T1053.005 -TestGuids $g -ShowDetailsBrief
PS C:\> Invoke-AtomicTest T1053.005 -TestGuids $g -CheckPrereqs
PS C:\> $log = 'C:\PurpleArtifacts\art.csv'
PS C:\> Invoke-AtomicTest T1053.005 -TestGuids $g -ExecutionLogPath $log
PS C:\> Invoke-AtomicTest T1053.005 -TestGuids $g -Cleanup

Each line has a purpose. The brief details print the command the test will run, so the operator confirms it before anything executes. The prerequisite check runs nothing, and reports what is missing. The execution log is the tool's own record of the run, with its time, host, user and exit code, which the defender reads beside the test log.

The cleanup takes the same GUID, so it removes exactly what the test made. The course uses Atomic Red Team for most single procedures and MITRE Caldera for chained operations, where an agent on the host runs one ability after another. The test log row the operator wrote for this run, PT-0103:

PurpleTestLog_CL
| where TestId == "PT-0103"
| project TimeGenerated, TestId, Technique, AtomicTestName, TargetHost, Operator,
    ExecutionStatus, CleanupTime

One row, the operator's account of the test:

Time      TestId   Technique  Test                  Status
--------  -------  ---------  --------------------  ---------
09:40:02  PT-0103  T1053.005  Scheduled task Local  Completed

The row is a promise. It tells the defender what should be visible: a process on NE-PT-WS01, under pt.operator, at 09:40, creating a task. If the defender cannot find those records, either the test did not do what the row says or the defense cannot see it, and both are worth knowing.

3

Run it: what the host recorded

The records the test left

The defender's first question is what the host recorded, before any rule is considered. Every process and device event on the workstation in the three minutes after the test started:

union
    (DeviceProcessEvents | project Timestamp, Table = "DeviceProcessEvents",
    What = FileName),
    (DeviceEvents | project Timestamp, Table = "DeviceEvents",
    What = ActionType)
| where Timestamp between (datetime(2026-09-15T09:40:00Z)
    .. datetime(2026-09-15T09:43:00Z))
| order by Timestamp asc

Four records, the whole test from start to cleanup:

Time      Table                What
--------  -------------------  --------------------
09:40:02  DeviceProcessEvents  cmd.exe
09:40:03  DeviceProcessEvents  schtasks.exe
09:40:05  DeviceEvents         ScheduledTaskCreated
09:41:32  DeviceEvents         ScheduledTaskDeleted

cmd.exe started schtasks.exe, Defender recorded the task being created, and ninety seconds later recorded it being deleted by the cleanup. That is full visibility: every step the procedure took left a record. Whatever happens next, the defense had what it needed to notice the test.

Each record carries the account and the process that made it, so the defender can tie it to the operator's row without guessing. schtasks.exe ran as pt.operator, under cmd.exe, at the time the row gives. A record from another account, or another host, at the same minute would belong to something else, and the defender would leave it out of the test's evidence rather than count it.

Reading the records before the alerts is the course's second habit. It separates two very different gaps: a step that was recorded and not alerted, which a rule can fix, and a step that left no record, which no rule can fix until something records it. A purple team that starts from the alerts cannot tell them apart.

4

The variant: the same task, created through WMI

T1053.005 test 6, run two days later as PT-0303

The operator reads the rule that is supposed to catch the test, and notices how narrowly it is written. PU-R02 as it stood on the first day:

DeviceProcessEvents
| where FileName =~ "schtasks.exe"
| where ProcessCommandLine has "/create"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine

The rule reads schtasks.exe with "/create" on its command line. Windows will register the same task without schtasks.exe running at all, and Atomic Red Team has a test for it: T1053.005 test 6, WMI Invoke-CimMethod Scheduled Task, GUID e16b3b75-dc9e-4cde-a23d-dfa2d0507b3b, which hands the Task Scheduler's WMI class a task definition in XML:

$xml = [System.IO.File]::ReadAllText("#{xml_path}")
Invoke-CimMethod -ClassName PS_ScheduledTask `
  -NameSpace "Root\Microsoft\Windows\TaskScheduler" `
  -MethodName "RegisterByXml" `
  -Arguments @{ Force = $true; Xml =$xml; }

The operator ran it on Thursday 17 September as PT-0303, with the same Invoke-AtomicTest steps. What the workstation recorded:

union
    (DeviceProcessEvents | project T = Timestamp,
    Record = strcat(FileName, " from ", InitiatingProcessFileName)),
    (DeviceEvents | project T = Timestamp, Record = ActionType)
| where T between (datetime(2026-09-17T15:40:00Z) .. datetime(2026-09-17T15:44:00Z))
| order by T asc

The task created and deleted, and PowerShell's command, with no schtasks.exe anywhere:

Time      Record
--------  --------------------
15:40:18  PowerShellCommand
15:40:19  ScheduledTaskCreated
15:42:18  PowerShellCommand
15:42:18  ScheduledTaskDeleted

Defender recorded the task, so the defense could have seen it, and PU-R02 had nothing to read: no alert followed. That is the conversation a purple team test starts. The operator's next move is always the procedure the rule does not read, and the defender's answer, a rule that reads the task itself rather than the tool that made it, comes from records like these.

5

Detection follows: the alert

What the rule noticed, and when

The defense's rules run on schedules over the records. PU-R02 runs every five minutes. The alerts in the twenty minutes after the test:

SecurityAlert
| where TimeGenerated between (datetime(2026-09-15T09:40:00Z)
    .. datetime(2026-09-15T10:00:00Z))
| project TimeGenerated, AlertName, AlertSeverity, CompromisedEntity

One alert, from the rule written for the test:

Time      Alert                                               Severity  Host
--------  --------------------------------------------------  --------  ----------
09:46:02  PU-R02 Scheduled task created from the command ...  Medium    NE-PT-WS01

The alert names the host and the account, which is what lets the defender match it to the test. It does not name the test, because the rule has no idea a test was running; it saw a scheduled task created from the command line by a standard account and reported it.

That is the right behavior for a rule, and it is why the purple team, not the rule, is responsible for tying each alert to the procedure that caused it.

Six minutes from the test to the alert is the rule working as scheduled: its next run after the record arrived found it and alerted. A test that stopped here would be reported as detected, and most detection testing does stop here. A purple team does not, because an alert is not yet a defense; it is a message to someone who has to act on it.

6

The verdict: the incident nobody opened

What the defense did with the alert

The last thing the defender reads is what happened to the alert: an incident opened, investigated and closed with a verdict, or nothing. For PT-0103's alert the answer is nothing:

SecurityIncident
| where CreatedTime between (datetime(2026-09-15T09:40:00Z)
    .. datetime(2026-09-15T10:00:00Z))
| count

The count is zero. Across the whole day the pattern is the same:

union
    (SecurityAlert | where TimeGenerated between (datetime(2026-09-15)
    .. datetime(2026-09-16)) | summarize N = count()
    | extend What = "Alerts"),
    (SecurityIncident | where CreatedTime between (datetime(2026-09-15)
    .. datetime(2026-09-16)) | summarize N = count()
    | extend What = "Incidents")
| project What, N

Six alerts on Tuesday, and one incident between them:

Record     Count
---------  -----
Alerts     6
Incidents  1

The one incident that was opened, for a Run key test twenty minutes later, was closed as benign within half an hour, with a comment noting that purple team testing was running that week.

That verdict is reasonable, and it is also a warning: an analyst who knows a test is running may close any alert that looks like one, including a real intrusion that happens in the same week. The course comes back to that risk in Module 8.

Five of the day's six alerts were never turned into incidents, PT-0103's among them. The rule worked, the record was complete, and the defense still did nothing with the test.

That is the finding a purple team exists to produce, and it is not a detection finding at all: it is about how alerts reach the people who handle them. The course's later modules follow this exact gap to its repair.

7

What purple teaming is, and is not

Four kinds of test, four questions

The word itself comes from mixing red and blue, the attacking and defending teams of an exercise, and it is sometimes used for any activity that puts them in a room together. This course means something narrower and more useful: a method in which both seats work one record and every test ends with a measured outcome, an owner and, where there is a gap, a repair and a retest.

Purple teaming is easiest to see beside the kinds of testing it is often confused with. Each answers a different question and changes something different:

Four kinds of security test

Red team

Who knowsThe defense, unwitting
What it answersWhether the intruder reached the objective
What it changesUsually a report

Penetration test

Who knowsThe system owner
What it answersWhich weaknesses can be exploited
What it changesFixes to the system

Detection test

Who knowsThe rule's author
What it answersWhether one rule fires on one procedure
What it changesThe rule

Purple team

Who knowsBoth seats, together
What it answersWhat the defense did with each step, to the verdict
What it changesRules, telemetry and process, then a retest

A red team measures the defense without telling it and reports what an intruder achieved; it rarely fixes anything itself. A penetration test finds exploitable weaknesses for the system's owner. A detection test checks one rule against one procedure.

A purple team runs procedures in the open, measures every step against the whole defense, from records to rules to the analyst's verdict, and repairs what it finds before retesting it. It is the only one of the four whose last step is proving the fix.

The four are complementary rather than competing. A mature program uses red teams to find out what an intruder could do unannounced, penetration tests to find weaknesses before an intruder does, detection tests as part of writing rules, and purple teams to turn all of it into measured, repaired and retested defenses. This course teaches the last, and borrows from the others only where a purple team needs to.

That is also why this course does not teach exploitation or evasion. A purple team operator needs to run procedures exactly and record them, not to hide them; the procedures come from documented sources, and the skill is in choosing, running and reading them.

It also explains where the operator's procedures come from. Every test in the course is either a published Atomic Red Team test, identified by its GUID, a Caldera ability from MITRE's published library, or a custom procedure whose exact command is in the test log.

Nothing is improvised, and nothing is hidden from the defense, because a procedure the defense cannot see coming is a red team's tool, not a purple team's.

8

The two seats

What each does in every test

Both seats work every test, and the course teaches both in every lesson. What each owns:

The two seats, in every test

Operator

Before the testChooses the procedure and its source
DuringRuns it as written; records the row
AfterPlans the variant the rule misses

Defender

Before the testPredicts the outcome from the rules
DuringWatches what arrives
AfterClassifies the outcome; repairs the gap

The before column is where most of the value is decided. An operator who chooses a procedure without a source cannot repeat it; a defender who predicts no outcome cannot be surprised by one. Lesson 1.4 and the capstone's planning lesson both start here, and the course's first lab is an exercise charter written before any test runs.

Neither seat is the other's opponent. The operator wants the defense to improve and runs procedures that will show where it does not; the defender wants to know the truth about the rules and reads the records rather than the dashboard.

In a small team one person holds both seats, which is how you will work through most of this course, and the discipline is in keeping the two records apart: what ran, and what the defense did with it.

9

The seven measures

How far a test got through the defense

The course measures every test on seven steps, from the procedure running to the defense responding. Each step has a short definition the whole course uses:

The seven measures
ExecutedThe procedure ran, by the operator's and the tool's records
TelemetryThe host or service recorded the step
PreventionA control stopped it, where one should
DetectionA rule alerted on it
Alert qualityThe alert was about the real activity
InvestigationSomeone opened and worked an incident
ResponseThe defense acted, and the verdict was right

A test is classified by the last step it reached. PT-0103 on all seven:

PT-0103 on the seven measuresExecutedrow CompletedTelemetryfour recordsPreventionnone expectedDetectionPU-R02, 6 minAlert qualitytrue activityInvestigationno incidentResponsenothing done
Green steps the test reached, red the steps where the defense stopped.

Prevention is grey rather than red because no control was expected to stop a standard account creating a scheduled task; that is an ordinary thing for Windows to allow. The measures do not demand that every step be blocked, only that the plan say which steps should be, so a missing block is a finding only where one was expected.

The test reached the fifth step and stopped. A report that said "detected" would be true and would hide the two red steps, which are where the defense actually failed. Module 9 of the course builds the whole engagement's measurement on these seven steps, and every test you read before then is classified the same way.

10

Validate

The test by its alert, and by everything that followed

The obvious way to report PT-0103 is by its alert:

First trythe alert after the test
SecurityAlert
| where TimeGenerated between (datetime(2026-09-15T09:40:00Z)
    .. datetime(2026-09-15T10:00:00Z))
| project TimeGenerated, AlertName, AlertSeverity, CompromisedEntity
1 alert. PU-R02 fired six minutes after the test: detected.
The alert is one measure of seven. Reading the record of what was created, the alert and the incident together shows where the defense stopped, which the alert alone hides.
Refinedthe task, the alert and the incident, in order
union
    (DeviceEvents | where ActionType == "ScheduledTaskCreated"
        | project Timestamp, Record = "task created"),
    (SecurityAlert | project Timestamp = TimeGenerated,
        Record = "alert"),
    (SecurityIncident | project Timestamp = CreatedTime,
        Record = "incident")
| where Timestamp between (datetime(2026-09-15T09:40:00Z)
    .. datetime(2026-09-15T10:00:00Z))
| order by Timestamp asc
2 records. The task created, the alert, and no incident.

The first try is not wrong, and that is what makes it dangerous. PU-R02 did fire, six minutes after the test, on the right host and account.

A dashboard counting detections would credit it, a coverage map would color the technique green, and the five unhandled alerts on the same day would never appear in either. The refined query costs two more lines and shows the step where the defense stopped.

The refined read is the one this course reports. On the chain both seats use, PT-0103 reads:

Outcome chain

PT-0103

Executed

Completed, cleaned up

Recorded

Four records

Alerted

PU-R02 at 09:46

Handled

No incident

Owner

SOC lead: the alert queue

Plan

Variants against PU-R02

What PT-0103 shows

Agreed by both seats.

  • The procedure ran as written and was cleaned up.
  • Fully recorded and alerted; never investigated.
  • A process gap, not a detection gap.

One test, read to the verdict: detected by the rule, unhandled by the defense.

The chain's owner row is worth noticing. The gap is not detection engineering's, because the rule worked; it belongs to whoever decides which alerts become incidents. Naming the right owner is half of fixing a gap, and a report that sent this one to the detection team would get a rule tuned that did not need tuning.

The chain is the course's shape for every result. You will fill it in for hundreds of steps by the capstone, and the habit of reading past the alert is the one this lesson exists to start.

11

Adapt: four outcomes the same test could have had

And what each would ask for

PT-0103 had one outcome. The same test, on a different defense, could have had any of four:

Four outcomes for one test

Detected

What the records would showAn alert, and an incident confirming it
VerdictA rule fired: YesThe defense acted: Yes

Alerted, not handled

What the records would showAn alert with no incident, as PT-0103 had
VerdictA rule fired: YesThe defense acted: No

Recorded only

What the records would showThe records, and no rule that read them
VerdictA rule fired: NoThe defense acted: No

Not visible

What the records would showNo record of the step at all
VerdictA rule fired: NoThe defense acted: No

None of the four is a pass or a fail on its own. A detected test with a forty-minute delay may be a failure for a step that needed stopping in five; a not-visible test may be acceptable for a host the plan said would not be monitored.

The outcome is a fact about the test, and whether it is good enough is a judgment the plan sets before the test runs.

Each outcome asks for different work from a different owner. Detected asks for nothing but a regression test. Alerted and not handled, PT-0103's outcome, goes to whoever runs the alert queue. Recorded only goes to detection engineering.

Not visible goes to the platform team, because no rule can read what is never recorded. Telling them apart is the skill the rest of the course builds, and it always starts from the records rather than the alerts.

Try

Read one test from both seats

The case below follows PT-0103 from the operator's row to the day's incidents. Work in the platform's Advanced hunting console with the Purple Range selected; every query runs against the course's recording.

The case is short, four questions, and it is the same shape as every case in the course: one step in the operator's seat and the rest in the defender's, each answered from a query you can see, change and run again.

Work the case in order. Each step's answer is used by the next, and the order is the order the course always reads a test in: the operator's row, the host's records, the rule's alert, and the defense's verdict. If an answer surprises you, rerun its query and read the rows before moving on; the console shows the same recording every lesson reads.

The fourth answer is the one to remember: the rule worked and the defense still did nothing. Every module of the course is, in the end, about finding answers like that one and fixing them.

Do

Practice

Read another test from both seats
your lab

The practice is in the console, against the recording; your own lab is built in Lessons 0.7 to 0.11.

In your labRead another test from both seats
1

Operator: the row

Open PT-0105, the service installed on Tuesday 15 September, and note its host, account, time and cleanup.

2

Defender: the records

Find its process and device records in the test's first five minutes.

3

Defender: the alert

Find the alert, if any, and the minutes from the test's start.

4

Defender: the verdict

Find the incident, if any, and read its comment.

5

Both: classify

The last of the seven measures the test reached, with the record that shows it.

What you should end up with: PT-0105 read on the seven measures, in the shape of this lesson's outcome chain.

Resources

Publishers revise these pages; where a page and this lesson disagree, the page is newer.