The Active Directory lab · Part 1 of 3

Managing accounts, OUs and Group Policy in my AD lab

Why I put my Windows machines in a domain, what that let me control, and how I used accounts, OUs, Group Policy and audit events to manage and troubleshoot endpoints.

Once I had more than one Windows machine to look after, logging into each one to change a setting stopped making sense. Active Directory became one of the tools I used most. It gave me one place to manage identities and policy, and it gave the activity I saw on Windows endpoints a context: which account, which machine, and whether that access was what I intended.

The domain, OU, group and GPO names below are examples, and every command output is labelled as example output. The reasoning, and the order I check things in, is how I run the domain.

Why a domain instead of local accounts

With local accounts, every machine is its own island. A password change, a new admin, or an audit setting has to be repeated per host, and nothing connects a logon on one machine to the same person on another. A domain changes three things:

  • One identity per person. An account exists once, in AD DS, and every domain-joined machine trusts it.
  • Policy that lands by location. Where a computer or user sits in the directory decides which Group Policy reaches it.
  • Evidence I can correlate. The domain controller records credential checks, so I can follow one account across machines.

What I could control

Example layout · names are illustrative

  • lab.exampledomain root
    • Lab Usersdaily accounts
    • Lab Adminsseparate admin accounts, tiered
    • Lab Computers
      • Workstationsdomain-joined clients
      • Serversfile server, member servers
    • Service Accountsno interactive logon

Group Policy objects

Linked to Lab Computers: turns on logon and account-management auditing for workstations and servers below it.

Pick a GPO to see its scope. A GPO linked high in the tree reaches everything below it, which is why the audit policy is linked to Lab Computers rather than to each machine.

Accounts and groups. Daily accounts and admin accounts are separate objects in separate OUs, so an admin account is never the one reading email. Access is granted to groups, not to people, so removing someone from a group removes the access everywhere at once.

PowerShellDomain controller · read-onlyExample output · substituted names and addresses

Purpose: list who holds admin rights

Before trusting any admin action in the logs, I check who is actually allowed to perform it.

Get-ADGroupMember -Identity "Lab Admins" | Select-Object Name, objectClass
Show output
Name            objectClass
----            -----------
adm-lab01       user
Tier1 Helpdesk  group
  1. adm-lab01 a separate admin account, never used for daily sign-in
  2. Tier1 Helpdesk nested group: its members inherit this access, so it needs its own review

Read-only. The nested group is the line to notice: a membership review that stops at direct members misses it.

Organizational units and Group Policy scope. An OU is where an object lives; a GPO linked to that OU applies to everything inside it, unless inheritance is blocked or security filtering narrows it. When a setting did not show up on a machine, the first question was always which OU the computer was in.

cmdWindows client · standard userExample output · substituted names and addresses

Purpose: see which GPOs reached this computer

When a policy seemed missing, I checked what the machine itself had received before editing anything on the domain controller.

gpresult /r /scope computer
Show output
COMPUTER SETTINGS
  CN=WS-01,OU=Workstations,OU=Lab Computers,DC=lab,DC=example
  Last time Group Policy was applied: 11/7/2026 at 8:02:11 AM
  Applied Group Policy Objects
      Restrict admin sign-in
      Workstation audit policy
  The following GPOs were not applied because they were filtered out
      Server baseline
          Filtering:  Not Applied (Empty)
  1. OU=Workstations the computer's location decides its policy
  2. Not Applied (Empty) this GPO has no settings for computers, so nothing was lost

Example output. The distinguished name on the first line answers most “why didn’t my policy apply” questions.

A delegated-access example

Not every task needs a domain admin. Resetting a lab user’s password is a good example: I want a helpdesk group to do it, and nothing else.

  1. Create a group, Helpdesk-Lab, and put the helpdesk accounts in it.
  2. On the Lab Users OU, delegate only “Reset user passwords and force password change at next logon” to that group.
  3. Test both directions: a helpdesk account resets a password in Lab Users, and the same account fails to reset an account in Lab Admins.
cmdDomain controller · read-onlyExample output · substituted names and addresses

Purpose: confirm what was delegated, and where

A delegation wizard is easy to click through; I wanted to read back exactly what permission the group ended up with.

dsacls "OU=Lab Users,DC=lab,DC=example" | findstr /i "Helpdesk-Lab"
Show output
Allow LAB\Helpdesk-Lab    SPECIAL ACCESS for Reset Password   <Inherited to user>
Allow LAB\Helpdesk-Lab    SPECIAL ACCESS for pwdLastSet       <Inherited to user>
  1. Reset Password the extended right to reset, not to read or change other attributes
  2. Inherited to user applies to user objects inside this OU only, not to Lab Admins

Example output for an example delegation. Keeping admin accounts in their own OU is what makes the boundary hold.

Groups, scope and the audit settings behind the evidence

Every event in the exercises below exists because of a setting I chose first. This is the layout I use, with the same illustrative names as the OU diagram:

Worked example layout · names and values illustrative

Control Where it applies What it sets Why I used it
Lab Admins group OU Lab Admins Two separate admin accounts; no daily account is a member An admin action can only come from an admin-only account, so any 4728 for this group is worth reading
Helpdesk-Lab group OU Lab Users only Delegated Reset Password, nothing else Least privilege: the right stops at daily accounts and never reaches Lab Admins
Password and lockout GPO Domain root Lockout after 15 bad attempts, 15-minute window Account policies for domain accounts only take effect from the domain root, so this is the one place it works
Workstation audit policy GPO OU Lab Computers Logon success and failure (4624, 4625); Special Logon success (4672); subcategory settings forced Workstations and member servers record who signed in and who used admin rights
Default Domain Controllers Policy Domain Controllers OU Credential Validation and Kerberos authentication failures (4776, 4771); User Account and Security Group Management success (4720, 4740, 4728) Domain controllers sit in their own OU and do not inherit the Lab Computers link, so their auditing is set separately
Restrict admin sign-in GPO OU Workstations Deny local and Remote Desktop logon to Lab Admins Admin credentials never land on a workstation; a refused attempt leaves a 4625 with sub status 0xC000015B

Force audit policy subcategory settings has to be on, or a legacy category setting can quietly override the advanced ones and the events I expect never appear.

Sign-in and account audit evidence

Group Policy decides what Windows audits; the hosts decide where it is written. These are the events I lean on, and where each one appears:

Event Meaning Where it is recorded
4624 / 4625 Logon succeeded / failed The machine that processed the logon
4771 / 4776 Kerberos pre-auth failed / NTLM credential check The domain controller
4740 Account locked out The domain controller holding the PDC emulator role
4720 User account created Domain controller
4728 / 4732 Member added to a global / local security group Domain controller / the machine
PowerShellDomain controller · read-onlyExample output · substituted names and addresses

Purpose: find recent lockouts and their source

When someone could not sign in, I wanted the lockout's caller computer before resetting anything, so the next lockout would not follow straight away.

Get-WinEvent -FilterHashtable @{ LogName = 'Security'; Id = 4740 } -MaxEvents 3 | ForEach-Object { $x = [xml]$_.ToXml(); [pscustomobject]@{ Time = $_.TimeCreated; Account = $x.Event.EventData.Data[0].'#text'; Caller = $x.Event.EventData.Data[1].'#text' } }
Show output
Time                 Account    Caller
----                 -------    ------
2026-10-28 17:42:10  lab-user04  WS-03
  1. Caller the machine that kept sending the bad password, often a saved credential

Example output. The caller computer is the lead: it points at the mapped drive, service or session still using the old password.

A failed-logon investigation

The pattern I practise is short: read the sub status, find the source workstation, then look for what on that workstation is retrying. A sub status of 0xC000006A means the account exists and the password was wrong; 0xC0000064 means the account does not exist, which looks more like guessing.

What I wanted to learn from a Windows logon goes through the fields one by one, and SOC-0142 walks a simulated cluster of seven failures from first alert to an analyst’s decision.

Attack-lab exercises

The domain is also where I practise the other side: doing something an attacker or a careless admin might do, inside the lab, and checking that each layer saw it. My red and blue exercise VMs (VM 301 and 302) exist for this. Every exercise below has the same shape: an objective, a scope that stays inside the lab domain, the technique, the action, what Windows recorded, what the SIEM said, how I respond and the result.

These are practice walkthroughs: the outputs are written for this entry, and each result says so. The ATT&CK IDs are a mapping I added for this write-up, so a reader can place each exercise in a shared vocabulary.

Wrong passwords against one lab account

Practice walkthrough · substituted names and addresses
Objective
See what a burst of wrong passwords leaves on each machine, and how the SIEM turns those events into alerts.
Lab scope
One lab test account (student01), one lab workstation (WS-02) and the lab file server (FS-01). Nothing outside the lab domain.
Technique
From WS-02, open a share on FS-01 as student01 and enter a wrong password 12 times, in two bursts of six about five minutes apart. The lockout threshold in this walkthrough is 15, so the account is not locked.
Command or action
PowerShell · FS-01 · read-only
Get-WinEvent -FilterHashtable @{ LogName = 'Security'; Id = 4625; StartTime = (Get-Date).AddMinutes(-30) } | Measure-Object
Windows evidence
12 events 4625 on FS-01: logon type 3, sub status 0xC000006A (real account, wrong password), workstation WS-02. The domain controller records the matching credential checks.
SIEM finding
Two alerts for "multiple failed logons", one per burst. The 12 events behind them are traced one by one in the SIEM design entry.
Response
Confirm WS-02 is the practice host and student01 the practice account, check WS-02 for a saved credential, then close both alerts as expected exercise activity with the exercise ID in the note.
Result
Practice walkthrough. No recorded run yet.

ATT&CK mapping: T1110.001 Brute Force: Password Guessing

An unexpected change to an admin group

Practice walkthrough · substituted names and addresses
Objective
Check that adding someone to an admin group is visible within minutes, with the account that made the change.
Lab scope
The Lab Admins group, one lab test account and one lab admin account, on the lab domain controller.
Technique
Signed in as the lab admin, add the test account to Lab Admins, wait five minutes, then remove it.
Command or action
PowerShell · Domain controller · read-only
Get-WinEvent -FilterHashtable @{ LogName = 'Security'; Id = 4728, 4729 } -MaxEvents 4 | Select-Object TimeCreated, Id, Message
Windows evidence
Event 4728 (member added to a security-enabled global group) and 4729 (member removed) on the domain controller. Each names the group, the member and the subject account that made the change.
SIEM finding
One alert for "member added to a privileged group". The removal arrives as a low-severity event that I attach to the same case.
Response
Compare the change with what I meant to do, confirm the subject account is mine, confirm the removal, and record both events in the case.
Result
Practice walkthrough. No recorded run yet.

ATT&CK mapping: T1098.007 Account Manipulation: Additional Local or Domain Groups

An admin account signing in to a workstation

Practice walkthrough · substituted names and addresses
Objective
Confirm that the policy keeping admin accounts off workstations actually refuses the sign-in, and that the refusal is visible.
Lab scope
One lab admin account (adm-lab01) and one lab workstation (WS-01) in the Workstations OU.
Technique
Try to sign in to WS-01 at the keyboard as adm-lab01 after the "Restrict admin sign-in" GPO has applied.
Command or action
cmd · WS-01 · standard user
gpresult /r /scope computer | findstr /i "Restrict"
Windows evidence
With the policy applied: event 4625 on WS-01, logon type 2, status 0xC000015B (the account is not granted this logon type). Without it: event 4624, which is the finding.
SIEM finding
Expected: one failed-logon event for an admin account, which the rule raises above an ordinary failure because of the account name. A 4624 for adm-lab01 on a workstation would be the alert to investigate.
Response
If the sign-in succeeded, run gpresult on WS-01 to see whether the GPO reached it, and fix its OU or link before anything else.
Result
Practice walkthrough. No recorded run yet.

ATT&CK mapping: T1078.002 Valid Accounts: Domain Accounts

The Kali Red and Blue page works the same domain from both sides, including a failed-logon search that came back empty because of a time-zone filter.

What the endpoint and the SIEM each told me

Putting the endpoint’s events next to the SIEM’s alerts for the same exercise is the comparison I get the most out of. In the first exercise’s example, Windows records 12 events and the SIEM raises two alerts. Neither number is wrong. The endpoint writes down every attempt, with the sub status that says whether the account exists. The SIEM writes down every time a rule’s threshold was crossed.

So the alert count tells me how many times a pattern happened, and the event count tells me how many attempts there were. The gap between the two bursts is only visible on the endpoint side, and it is the best lead: something retrying on a timer looks very different from a person retyping. The SIEM design entry traces all 12 events into those two alerts.

Wi-Fi with domain accounts

An AD-backed 802.1X Wi-Fi network is a natural next step, and I have written it up as a design in Who should get onto the lab Wi-Fi?. It is written as a practice design, with an example access point, NPS policy and test accounts.

What I learned

A domain is only as useful as the answers it lets me give. Location in the OU tree explains most policy surprises, groups explain most access, and the audit policy decides whether there is any evidence at all. When an exercise and its evidence disagree, the disagreement points at the layer to fix.

Takeaway: for every Windows question, write down three things before searching: which machine should have recorded it, which event ID it would be, and which GPO turned that auditing on.

Further reading: AD DS overview · Event 4625 · Delegation of control

Skills used

  • Group-based access and separate admin accounts
  • Checking Group Policy scope with gpresult
  • Audit policy and lockout troubleshooting
  • Planning attack-lab tests by the events they should leave

All skills, grouped by what job postings ask for

Tools in this entry

Every tool and its documentation