In this section

0.6 The Practice Lab and the Sample Month

Module 0

Introduction

Every query in this course runs in a practice lab built into the page, with nothing to install and no account to configure, against one month of records from a single company. This sub introduces both, and sets out exactly how far the lab can be trusted to behave like a real workspace.

The company is Northgate Engineering, an 810-person engineering firm that runs on Microsoft 365, with Microsoft Sentinel and Microsoft Defender watching it. The month runs from 13 February to noon on 15 March 2026. Its records are mostly the ordinary work of a company, as any real month's would be: people signing in, sending mail, opening documents, running programs.

Among them, recorded exactly as the tools would have recorded them, are several attacks of the kinds security teams face: password attacks, stolen sessions, malicious applications granted access to mailboxes, data taken from file shares, and a ransomware infection. The course finds them module by module, and this sub deliberately says no more about them than that.

You'll measure the whole lab in one query and see the fixed moment it treats as now. You'll count who signed in during the month. Then you'll see the four ways the lab differs from a real workspace, so that everything learned here works there unchanged.

The practice lab: one company, one month, real table names Northgate Engineering 810 staff, Microsoft 365, Sentinel and Defender The sample month 13 February to noon on 15 March 2026 21 tables, 105,111 rows ordinary work and several attacks Where the lab differs from a workspace one month, no row limits a subset of columns lenient with some names counts rows, not speed Everything learned in the lab works in a workspace; the differences are listed so nothing has to be unlearned.

The diagram is the lab in summary; the row count and the dates in it come from queries in this sub. One company, one month, 21 tables with real names and real columns. Below it are the four ways the lab is not a workspace, each explained in this sub so that none of them comes as a surprise later.

01

A Company and a Month

Northgate Engineering

Northgate Engineering is a fictional company built to be realistic: an engineering firm based in Manchester, with a second site in Bristol, staff who travel, contractors and partners with guest accounts, and an IT team that administers Microsoft 365, Entra ID and a handful of Linux servers.

Its security tools are the ones this course queries: Sentinel collecting its logs, and Defender's products watching its devices, mail, identities and cloud applications.

The sample month is a month of that company's records, from all of the tables Section 0.3 introduced, generated so that every table is consistent with every other: a sign-in in one table matches a device logon in another, an email that arrives is followed by the recipient's activity, a process that starts on a laptop appears with its parent.

That consistency is what lets later modules join tables and follow activity across them, as an investigation in a real workspace would.

union SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs,
    AuditLogs, DeviceProcessEvents, DeviceNetworkEvents, DeviceFileEvents,
    DeviceLogonEvents, DeviceEvents, DeviceRegistryEvents, DeviceInfo, EmailEvents,
    OfficeActivity, CloudAppEvents, SecurityAlert, AlertEvidence, SecurityIncident,
    Syslog, CommonSecurityLog, IdentityLogonEvents, IdentityInfo
| count

One union across all 21 tables, ending in a count, measures the whole lab. It holds 105,111 rows. That is small by the standard of a real workspace, which might receive that many rows in minutes, and large enough that no question can be answered by reading. Every answer has to be found with a query, which is the point.

A fictional company has another advantage over real data, beyond consistency: nothing in it belongs to anyone. Every account, address and message can be shown, discussed and queried without any concern for privacy, which is what lets the course show real results rather than descriptions of them.

The company also has people with roles that appear throughout the course, named and consistent from module to module: a chief information security officer, SOC analysts, a security architect, an IT director, ordinary staff in engineering and finance. Their accounts behave as those roles would, which is what makes ordinary activity look ordinary and unusual activity stand out.

Generated data has limits worth admitting. Real organizations are messier than any generator: their logs have gaps, their users do strange things for good reasons, and their attackers improvise. The sample month includes some of that mess, such as missing values and devices that report little, because a dataset without it would teach habits that fail on real data.

02

The Fixed Present

What now means here

Real data keeps arriving, so the same query run tomorrow covers different rows and returns a different answer. The lab's data never changes, and its present never moves either.

print Now = now(), DayAgo = ago(1d), WeekAgo = ago(7d)

print shows three times at once. now() returns noon on 15 March 2026, the end of the sample month, every time. ago(1d) is noon on 14 March and ago(7d) noon on 8 March, for everyone who runs the query. That makes every number in the course reproducible, by anyone, at any time: when a sub says a query returns 338, it returns 338 for you too.

The completed query below asks the lab for the time.

The same moment, whenever and wherever you happen to run it from. Queries in the course that use ago() are written with this fixed present in mind; the same queries in a real workspace would cover the last day or week before whenever they ran.

A fixed present also makes predictions testable. Before running a query, you can write down what you expect; the lab will always give the same answer, so the comparison is fair, and the habit of predicting is worth more than any single query, as Section 0.7 explains.

The fixed present is also why some course queries name dates and others use ago(). A query about a particular incident names its dates, because the incident happened when it happened. A query about recent activity uses ago(), which in the lab always means the end of the sample month and in a workspace means the moment the query runs.

03

Who Is in the Month

A sample of the company

The lab holds the people and machines its month needs rather than the whole company of 810. That keeps it small enough to run in a browser while keeping every story complete.

SigninLogs
| summarize Accounts = dcount(UserPrincipalName),
    Guests = dcountif(UserPrincipalName, UserPrincipalName contains "#EXT#")

Counting distinct accounts, and separately the guests among them, describes the people in the month. 101 accounts signed in interactively, 8 of them guests from partner organizations, recognizable by the #EXT# in their names.

The company has 810 staff; the lab includes the accounts whose activity the month's events involve, together with enough ordinary users to make normal activity look normal. Section 0.3's tables hold a similar sample of devices and servers.

For learning, the sample is an advantage rather than a compromise. A question about every account can be answered and read in full; a pattern that would be one line in ten thousand in a real workspace is one line in a hundred here, which makes it findable while the technique is being learned.

Guests are worth noticing early, before any query depends on telling them apart. Their names look different from staff names, with the partner's domain folded in before #EXT#. Queries that assume every account is an employee miscount them, which is why counts of staff in this course separate guests where it matters.

The departments are the ones an engineering company would have: engineering, finance, sales, IT, operations, marketing and others, each with a dozen or so accounts in the sample. IdentityInfo records them, and queries that need to know who someone is, rather than only what they did, read it.

Devices follow the same principle. The lab's endpoint tables cover the laptops and servers whose activity the month needs, a small fraction of the company's 865 endpoints, together with enough ordinary machines to show what normal looks like on a device.

04

Where the Lab Differs

Lenient where a workspace is strict

The lab runs real KQL against real table and column names, and for nearly everything in this course it behaves as a workspace does. In a few places it is more lenient, and those are worth knowing so that habits formed here do not fail elsewhere.

SigninLogs
| WHERE ResultType != "0"
| count

The first difference is about case, and it is harmless if operators are always written in lower case. The lab accepts WHERE in capitals and returns 338. Microsoft documents KQL as case-sensitive for operators as well as names, so a workspace would reject the same query. The course writes every operator in lower case; doing the same in the lab costs nothing and avoids the problem entirely.

Section 0.1 made the same point about table names, which the lab, like a workspace, does treat as case-sensitive. Operators are the exception, and only in the lab.

SigninLogs
| where Country == "GB"
| count

The second difference is quieter, and it matters more, because it produces a plausible answer instead of an error message that names the problem directly. A filter on Country, a column the sign-in table does not have, returns a count of zero in the lab.

The lab's tables carry the subset of each real table's columns that the course uses, so it cannot tell an invented column from a real one it does not hold, and treats the name as empty. A workspace knows its full schema and reports that the name cannot be resolved. The habit that works in both is Section 0.2's: check names with getschema before relying on them.

The exercise below replaces the invented column with the real one.

7,779 sign-ins from Great Britain, almost the whole of the month's 8,203, which is what a company based in Manchester should show. The lab's zero for Country was not an answer about geography; it was the lab's way of saying nothing, where a workspace would have said the column does not exist.

The two leniencies so far, and the two in Section 06, have something in common: each lets a mistaken query run. Neither changes the answer to a correct query. That is why the course can use the lab without hesitation and why its advice is simply to write correct queries, which then behave the same everywhere.

There is a practical way to keep lab habits honest. Any query worth keeping can be pasted into a real workspace or into Advanced Hunting, with the period adjusted, and run there. If it fails, the failure points at one of the differences in this sub, and the fix is the same in both places.

A workspace is also stricter about types in places where the lab follows it exactly: comparing a text column with a number by size fails in both, as Section 0.2 showed, and grouping by a value taken from a dynamic column without converting it fails in both. Where the lab is strict, it is strict for the same reasons a workspace is.

05

Using the Lab

Record, routine and the common mistakes

Across the sub, the lab turned out to be one company and one month, held still and measured: 105,111 rows, a fixed present, a sample of people and machines. It is lenient in a few ways a workspace is not, and the course's habits make those differences harmless.

The record collects what to remember about the lab, in the order the sub introduced it.

The practice lab

What to remember

Company

Northgate Engineering, 810 staff, Microsoft 365

Period

13 February to noon on 15 March 2026

now()

fixed at noon on 15 March

Data

21 tables, 105,111 rows, real names and columns

Contents

ordinary work and several attacks

Differences

fixed month, column subset, lenient names, no timing

The last row lists the four differences in brief; Sections 04 and 06 cover them in full. None changes what a correct query returns; each only changes how a mistaken query behaves.

Using the lab well
1Predict before running
write the number you expectthen compare
2Change one thing and rerun
a filter, a groupingsee what moved
3Write as for a workspace
lower-case operators, real columnsTimestamp on Defender tables
4Treat its numbers as facts
they are fixed and reproduciblecheck yours against them
The lab is a fixed world; every number in it can be reproduced and checked.

The first rung is the one that turns reading into learning, and it costs only a moment. Writing down the number you expect before running a query, and comparing, is what builds an intuition for data; a query whose result is never predicted teaches only its syntax.

Three lab mistakes
Rely on the lab's leniency
WHERE fails in a workspace.Write lower case
Read a zero from an unknown column
A workspace would error.getschema first
Expect the real time
now() is fixed.Use the month's dates
Write every query as if it will run in a real workspace; then it will.

The first mistake is the one most likely to follow a learner into a workspace, months after the lab, because the lab never complains. Writing every query in the form a workspace requires keeps lab practice and real work identical.

The second rung is how the lab teaches operators. Change one filter and rerun; group by one more column and rerun; the difference between the two results is exactly what the change did. Because the data never moves, the only thing that changed is the query.

The fourth rung is about trust. When your query returns a different number from the one a sub quotes, the difference is information: either the query asks something slightly different, or it contains a mistake. Working out which is some of the most useful practice the course offers, and the lab's fixed data guarantees there is always a definite answer.

06

Time Columns and Limits

Two more differences

Two further differences concern time and scale, and neither affects a correctly written query. The first is the time column on Defender's tables.

DeviceProcessEvents
| summarize ByTimestamp = countif(Timestamp > ago(1d)), ByTimeGenerated = countif(TimeGenerated > ago(1d))

Counting the last day's process starts twice, once on each time column, shows the difference. Filtering Defender's process table on Timestamp or on TimeGenerated gives the same count. A Sentinel workspace holding Defender data carries both columns on those tables, and the lab answers both; Advanced Hunting has Timestamp. Section 0.4 explained why the course writes Timestamp for Defender's tables, and this is the reason: it works everywhere.

The second is scale, and it is the one the lab can explain but not demonstrate. The lab holds one month and enforces no look-back window and no row limits, because its tables are small enough not to need them.

Module 10 cites Microsoft's documented limits for Advanced Hunting and Log Analytics and shows what they would do; the lab can show the arithmetic but not the failure. It also cannot measure speed. Module 10's advice on making queries fast comes from Microsoft's documentation, and the lab shows only the rows each step processes, which is what that advice is about.

None of these differences affects the course's numbers. Every figure quoted in a sub was produced by the lab, and the same query in a workspace holding the same data would produce the same figure; the differences only change what happens when a query is wrong, or when the data is far larger.

07

What the Month Holds

Ordinary work, and attacks within it

What the month holds is best seen from its ordinary rhythm first, because everything unusual is measured against it. Counting sign-ins per day and setting weekdays beside weekends shows that rhythm in one query.

SigninLogs
| summarize SignIns = count() by Day = startofday(TimeGenerated)
| extend Weekend = dayofweek(Day) in (0d, 6d)
| summarize Days = count(), Fewest = min(SignIns), Most = max(SignIns) by Weekend

Weekdays carry 321 to 425 interactive sign-ins each, weekend days 72 to 122, a ratio of roughly four to one. Most of the month is ordinary: about 8,000 interactive sign-ins, 15,000 messages, 9,500 program starts, the routine administration of a directory.

That ordinary activity matters as much as the attacks, because an attack is recognized by how it differs from the ordinary, and every module spends time establishing what normal looks like before looking for what is not.

Within that ordinary activity, the month holds several attacks of the kinds that real organizations face: attempts to guess or spray passwords, sessions taken over from outside, malicious applications granted access to mailboxes and files, data taken from file shares, and a ransomware infection.

None is announced, and none is labeled in the data. Some raised alerts and some raised none, as in real organizations, and the course finds each through the techniques of the module it belongs to: filtering and summarizing first, then joins, parsing, functions, time series and graphs.

This sub stops there deliberately, and so does the rest of Module 0. Finding the attacks is the course; knowing in advance which accounts, which addresses and which hours would turn the investigations into exercises in confirming an answer. Each module adds to the picture, and by Module 10 the month is understood from its first event to its last.

The attacks also overlap with ordinary work in ways that make them hard to see. A stolen session signs in to the same applications as its owner; a malicious application reads mail through the same interfaces as a legitimate one. The same is true of the others. The techniques the course teaches exist because attacks look like work until something about them is counted, compared or connected.

The order the course finds them in is the order of its techniques, not of the attacks. Some of the month's latest events are found early, because a simple filter shows them; some of its earliest are found late, because only a join or a graph connects them to anything. By the end, they fit together into one picture of the month.

08

The Shape of the Month

Your turn

The exercise draws the month's working rhythm: interactive sign-ins per day, from the first day to the last.

The grader checks for a row on 15 March, the month's last, partial day. If you got one row, the grouping is missing; if days appear out of order, add the sort.

The query is the same shape as Section 07's, without the split into weekdays and weekends, so every day is visible. Read the rows as the month's heartbeat, the ordinary pattern that every attack in the month has to hide inside.

Weekdays carry three or four hundred sign-ins, weekends a hundred or so, and the last day stops at noon. Every finding in the course stands out against that rhythm, and a day that breaks it is often the first thing worth a closer look.

Practice

Predict before running, change one thing and rerun, write as for a workspace, and treat the lab's numbers as facts.

The next sub, Section 0.7, sets out how the course takes you from your first query to mastery.