This lab builds a working Active Directory environment on Hyper-V: two domain controllers, a member server, and a client, on an isolated network. It is the foundation for practising Group Policy, certificate services, replication troubleshooting, and every AD-adjacent topic worth knowing.
Everything runs on a single machine with 32 GB of RAM. Evaluation ISOs from Microsoft are free: 180 days for Windows Server 2022, 90 days for Windows 11 Enterprise.
What you will build#
Domain: lab.internal. Never use a domain name you do not control, and never .local — it collides with mDNS.
Prerequisites#
- Windows 10/11 Pro or Windows Server with Hyper-V enabled
- 32 GB RAM (16 GB works if you run three VMs instead of four)
- 200 GB free on an SSD
- Windows Server 2022 and Windows 11 evaluation ISOs
Enable Hyper-V if it is not already:
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
# Reboot required
Step 1 — Networking#
Create an internal switch. Internal, not private: the host gets an adapter on it, which lets you provide NAT for updates.
New-VMSwitch -Name "LAB-Internal" -SwitchType Internal
# The host's adapter on that switch becomes the lab's gateway
$ifIndex = (Get-NetAdapter -Name "vEthernet (LAB-Internal)").ifIndex
New-NetIPAddress -IPAddress 10.10.10.1 -PrefixLength 24 -InterfaceIndex $ifIndex
New-NetNat -Name "LAB-NAT" -InternalIPInterfaceAddressPrefix 10.10.10.0/24
Verify:
Get-NetNat
Get-NetIPAddress -InterfaceIndex $ifIndex | Format-Table IPAddress, PrefixLength
Use a checkpoint after each major stage.
Checkpoint-VM -Name DC01 -SnapshotName "pre-dcpromo"costs seconds and saves you rebuilding when an experiment goes wrong. That is the entire point of a lab.
Step 2 — Create the VMs#
$vmPath = "D:\Hyper-V"
$isoServer = "D:\ISO\WindowsServer2022.iso"
function New-LabVM {
param([string]$Name, [int64]$MemoryGB, [string]$Iso, [switch]$Windows11)
New-VM -Name $Name -MemoryStartupBytes ($MemoryGB * 1GB) `
-Generation 2 -Path $vmPath `
-NewVHDPath "$vmPath\$Name\$Name.vhdx" -NewVHDSizeBytes 80GB `
-SwitchName "LAB-Internal"
# Windows 11 needs 4 GB, so it gets no dynamic-memory floor below that
$minMemory = if ($Windows11) { $MemoryGB * 1GB } else { 1GB }
Set-VM -Name $Name -DynamicMemory `
-MemoryMinimumBytes $minMemory -MemoryMaximumBytes ($MemoryGB * 1GB) `
-AutomaticCheckpointsEnabled $false -CheckpointType Production
Set-VMProcessor -VMName $Name -Count 2
Add-VMDvdDrive -VMName $Name -Path $Iso
$dvd = Get-VMDvdDrive -VMName $Name
Set-VMFirmware -VMName $Name -FirstBootDevice $dvd `
-EnableSecureBoot On -SecureBootTemplate MicrosoftWindows
if ($Windows11) {
# Windows 11 setup refuses to install without TPM 2.0
Set-VMKeyProtector -VMName $Name -NewLocalKeyProtector
Enable-VMTPM -VMName $Name
}
}
New-LabVM -Name "DC01" -MemoryGB 4 -Iso $isoServer
New-LabVM -Name "DC02" -MemoryGB 4 -Iso $isoServer
New-LabVM -Name "FS01" -MemoryGB 4 -Iso $isoServer
New-LabVM -Name "WS01" -MemoryGB 4 -Iso "D:\ISO\Windows11.iso" -Windows11
The Windows 11 client is the one VM with hard requirements. Microsoft's VM requirements for Windows 11 on Hyper-V are Generation 2, Secure Boot, a virtual TPM, at least 4 GB of memory, two or more virtual processors and 64 GB of disk. Without -Windows11 the script creates no vTPM, and Windows 11 setup will refuse to install. The virtual TPM is emulated, so the host does not need a physical TPM of its own. The local key protector ties the VM to this host: move it to another machine and it may not start until its key protector is updated.
Why AutomaticCheckpointsEnabled $false? This is advice, not a correctness fix. Every checkpoint is an .avhdx differencing disk beside the .vhdx, so checkpoints Hyper-V takes on its own cost disk space. They also clutter the list with entries you did not choose to make. In a lab you want only the checkpoints you took deliberately, with names you chose. -CheckpointType Production makes those checkpoints use VSS inside the guest. That gives you a data-consistent image rather than a snapshot of running memory. It is already the default for new VMs, but the script states it so nobody has to guess.
Rolling a domain controller back is less dangerous than it used to be. Windows Server 2012 and later DCs read the VM-Generation ID that Hyper-V exposes. When a checkpoint is applied, that ID changes. The DC notices the mismatch, resets its invocation ID and discards its RID pool. Its partners then treat it as a new replication source and replicate back what it lost. That prevents both USN reuse and duplicate SIDs. The old failure, where AD detects USN rollback and quarantines the DC, applies only to DCs that cannot see a Generation ID: Windows Server 2008 R2 and earlier, or a hypervisor that does not provide one.
Safe restore is not a backup strategy. Microsoft's own checkpoint documentation warns that a checkpoint is not a full backup and can cause consistency problems for replicated systems such as Active Directory. Safe restore only works if another DC still holds the changes. Roll back your only DC and everything since that checkpoint is gone. Applying checkpoints in this lab is fine — that is what a lab is for — but protect real DCs with Windows Server Backup or a system-state backup, not hypervisor checkpoints.
Step 3 — Promote the first domain controller#
Install Windows Server on DC01, then configure networking:
Rename-Computer -NewName "DC01" -Restart
New-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress 10.10.10.10 `
-PrefixLength 24 -DefaultGateway 10.10.10.1
# Points at itself — corrected after promotion
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses 127.0.0.1
Promote it:
Install-WindowsFeature AD-Domain-Services, DNS -IncludeManagementTools
Install-ADDSForest `
-DomainName "lab.internal" `
-DomainNetbiosName "LAB" `
-ForestMode "WinThreshold" `
-DomainMode "WinThreshold" `
-InstallDns:$true `
-SafeModeAdministratorPassword (Read-Host -AsSecureString "DSRM password") `
-NoRebootOnCompletion:$false `
-Force:$true
After reboot, verify:
Get-ADDomain
Get-ADForest
dcdiag /v /c
dcdiag should pass every test. Investigate any failure now — a broken forest root only gets harder to diagnose once you add a second DC.
Step 4 — Second domain controller#
Configure DC02 with 10.10.10.11 and DNS pointing at 10.10.10.10 — it must resolve the domain to find it.
Install-WindowsFeature AD-Domain-Services, DNS -IncludeManagementTools
Install-ADDSDomainController `
-DomainName "lab.internal" `
-Credential (Get-Credential "LAB\Administrator") `
-InstallDns:$true `
-SafeModeAdministratorPassword (Read-Host -AsSecureString "DSRM password") `
-Force:$true
Once up, fix DNS on both so each prefers its partner and falls back to itself. This avoids the classic "island" problem where a DC that only knows itself cannot start AD services cleanly after a restart:
# On DC01
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses 10.10.10.11,127.0.0.1
# On DC02
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses 10.10.10.10,127.0.0.1
Verify replication:
repadmin /replsummary
repadmin /showrepl
Get-ADReplicationPartnerMetadata -Target "lab.internal" -Scope Domain |
Format-Table Server, Partner, LastReplicationSuccess
Step 5 — DHCP and OU structure#
Install DHCP on DC01 for the client subnet:
Install-WindowsFeature DHCP -IncludeManagementTools
Add-DhcpServerInDC -DnsName "DC01.lab.internal" -IPAddress 10.10.10.10
Add-DhcpServerv4Scope -Name "LAB" -StartRange 10.10.10.100 `
-EndRange 10.10.10.200 -SubnetMask 255.255.255.0
Set-DhcpServerv4OptionValue -ScopeId 10.10.10.0 `
-DnsServer 10.10.10.10,10.10.10.11 `
-Router 10.10.10.1 -DnsDomain "lab.internal"
Build an OU structure worth practising against — mirroring how real environments separate by function rather than dumping everything in Users:
$base = "DC=lab,DC=internal"
New-ADOrganizationalUnit -Name "LAB" -Path $base
New-ADOrganizationalUnit -Name "Users" -Path "OU=LAB,$base"
New-ADOrganizationalUnit -Name "Servers" -Path "OU=LAB,$base"
New-ADOrganizationalUnit -Name "Clients" -Path "OU=LAB,$base"
New-ADOrganizationalUnit -Name "Groups" -Path "OU=LAB,$base"
New-ADOrganizationalUnit -Name "Service Accounts" -Path "OU=LAB,$base"
# Populate with test users
1..25 | ForEach-Object {
$name = "user{0:D2}" -f $_
New-ADUser -Name $name -SamAccountName $name `
-UserPrincipalName "$name@lab.internal" `
-Path "OU=Users,OU=LAB,$base" `
-AccountPassword (ConvertTo-SecureString "LabP@ssw0rd!" -AsPlainText -Force) `
-Enabled $true -ChangePasswordAtLogon $false
}
Step 6 — Join and verify#
Join FS01 and WS01 to the domain:
Add-Computer -DomainName "lab.internal" `
-Credential (Get-Credential "LAB\Administrator") `
-OUPath "OU=Servers,OU=LAB,DC=lab,DC=internal" `
-Restart
Verification checklist — all of these should succeed:
nltest /dsgetdc:lab.internal # locates a DC
gpresult /r # policy applies
Test-ComputerSecureChannel -Verbose # secure channel healthy
Resolve-DnsName _ldap._tcp.lab.internal -Type SRV # SRV records present
What to practise next#
The lab exists so you can break things safely. In rough order of value:
- Group Policy — build a baseline GPO, apply security filtering, use WMI filters, and work out precedence with
gpresult /h report.html. - Fine-grained password policies — a PSO applied to a group, overriding the domain default.
- AD Certificate Services on FS01, then issue certificates via autoenrolment.
- Break replication deliberately — take DC02 offline for longer than the tombstone lifetime and learn what recovery involves.
- Seize FSMO roles after simulating the permanent loss of DC01.
ntdsutilis not a tool you want to learn during an outage. - Delegated administration — grant a helpdesk group password-reset rights on the Users OU only, then verify the boundary holds.
Checkpoint before each. Roll back after. That loop is worth more than any amount of reading.
Sources#
- Windows Server 2022 | Microsoft Evaluation Center — the 180-day evaluation period for Windows Server 2022.
- Windows 11 Enterprise | Microsoft Evaluation Center — the 90-day evaluation period for Windows 11 Enterprise.
- Install Hyper-V in Windows and Windows Server — Pro/Enterprise requirement and the
Enable-WindowsOptionalFeaturecommand. - Set up a NAT network — internal switch, gateway address and
New-NetNatprocedure. - Install-ADDSForest (ADDSDeployment) —
WinThresholdfunctional level and the loopback DNS default on the first DC. - Virtualized Domain Controller Architecture — VM-Generation ID safe restore (invocation ID reset, RID pool discarded) and quarantine only where no Generation ID is provided.
- Windows 11 requirements — VM requirements: Generation 2, Secure Boot and vTPM on Hyper-V, 4 GB memory, two virtual processors, 64 GB storage; vTPM emulated independently of the host TPM.
- Hyper-V Generation 2 Virtual Machine Security Features — Secure Boot on by default, the
Microsoft Windowstemplate, and the key protector needing an update after a move to another host. - Set-VMKeyProtector (Hyper-V) —
-NewLocalKeyProtector. - Enable-VMTPM (Hyper-V) — enabling the virtual TPM.
- Set-VMFirmware (Hyper-V) —
-EnableSecureBootand-SecureBootTemplate. - Set-VMProcessor (Hyper-V) —
-Countfor the virtual processor count. - Using checkpoints — production versus standard checkpoints, the production default,
.avhdxstorage, and the warning that a checkpoint is not a backup for replicated systems such as AD. - RFC 6762: Multicast DNS —
.localreserved for mDNS; recommends against it for private unicast DNS. - Approved Resolutions | Special Meeting of the ICANN Board | 29 July 2024 —
.internalpermanently reserved for private use.
0 comments
Sign in to join the discussion.
No comments yet. If something here is wrong or incomplete, say so — corrections are welcome.