P03-T02 - AD Recovery and Time Baseline
Objective
Enable the forest recovery baseline, create the first System State recovery point on a dedicated disk, and configure the PDC Emulator to use external NTP peers.
Validated in the lab on Saturday, July 18, 2026, using QEMU Guest Agent only as execution transport. The production sysadmin runs the PowerShell directly on HQ-DC01.
Inputs
| Key | Validated value | Configurable parameter |
|---|---|---|
| Target | HQ-DC01 |
Run on the intended PDC Emulator |
| Domain | corp.gntech.me |
DomainFqdn |
| Backup disk | Proxmox scsi1, Windows Disk 1, 40 GB |
BackupDiskNumber |
| Backup volume | E: / DCBackup |
BackupDriveLetter |
| NTP peers | time.cloudflare.com,0x8, time.google.com,0x8 |
NtpPeers |
Target State
| Property | Required result |
|---|---|
| AD Recycle Bin | Enabled forest-wide |
| Windows Server Backup | Installed |
| Backup storage | Dedicated, non-boot, non-system disk |
| Recovery point | At least one successful System State version |
| PDC time | External manual peers; reliable time source |
| W32Time | Running and synchronized; not Local CMOS Clock |
Prechecks
- Complete and validate
P03-T01. - Run
dcdiag /test:Advertising /test:Services /test:SysVolCheck /test:NetLogons; stop on any failure. - Confirm which server owns the PDC Emulator role.
- Inspect the hypervisor before attaching storage. Do not assume Disk
1exists. - Never point this workflow at the OS disk or a disk containing customer data.
Current State Verification
On Proxmox, inspect the VM and attach a dedicated disk only if one is absent:
Validated lab correction:
Proxmox is used only to attach the virtual disk. Run the Windows automation directly on HQ-DC01.
From elevated PowerShell on HQ-DC01:
Get-Disk | Select-Object Number,PartitionStyle,IsBoot,IsSystem,@{n='SizeGB';e={[math]::Round($_.Size/1GB,2)}}
Get-Volume | Select-Object DriveLetter,FileSystemLabel,FileSystem
(Get-ADDomain).PDCEmulator
w32tm /query /source
The validated new disk appeared as Disk 1, RAW, IsBoot=False, IsSystem=False, and 40 GB. Stop if the intended disk is not RAW or its identity is ambiguous.
Execution
Copy the complete script below to HQ-DC01 or save it as Configure-HQ-DC01-RecoveryTime.ps1:
Show full recovery and time script
[CmdletBinding()]
param(
[string]$DomainFqdn = 'corp.gntech.me',
[string]$BackupDriveLetter = 'E',
[int]$BackupDiskNumber = 1,
[string[]]$NtpPeers = @('time.cloudflare.com,0x8','time.google.com,0x8'),
[switch]$StartSystemStateBackup,
[switch]$ValidateOnly
)
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
function Assert-Elevated {
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
throw 'Run this script from an elevated PowerShell session.'
}
}
function Get-RecoveryState {
$feature = Get-ADOptionalFeature -Identity 'Recycle Bin Feature'
$backupFeature = Get-WindowsFeature Windows-Server-Backup
$backupVolume = Get-Volume -ErrorAction Stop | Where-Object DriveLetter -eq $BackupDriveLetter
$backupDisk = Get-Disk -Number $BackupDiskNumber -ErrorAction SilentlyContinue
[pscustomobject]@{
Domain = (Get-ADDomain).DNSRoot
PdcEmulator = (Get-ADDomain).PDCEmulator
RecycleBinEnabled = ($feature.EnabledScopes.Count -gt 0)
BackupFeature = $backupFeature.InstallState
BackupDiskNumber = if ($backupDisk) { $backupDisk.Number } else { $null }
BackupDiskStyle = if ($backupDisk) { $backupDisk.PartitionStyle } else { 'Missing' }
BackupDiskIsBoot = if ($backupDisk) { $backupDisk.IsBoot } else { $null }
BackupDiskIsSystem = if ($backupDisk) { $backupDisk.IsSystem } else { $null }
BackupVolume = if ($backupVolume) { "$($backupVolume.DriveLetter):" } else { 'Missing' }
BackupVolumeLabel = if ($backupVolume) { $backupVolume.FileSystemLabel } else { '' }
TimeSource = ((w32tm /query /source) | Out-String).Trim()
W32TimeStatus = (Get-Service W32Time).Status
}
}
function Assert-ExistingBackupTargetSafe {
$volume = Get-Volume -ErrorAction Stop | Where-Object DriveLetter -eq $BackupDriveLetter
if (-not $volume) { return }
$partition = Get-Partition -DriveLetter $BackupDriveLetter -ErrorAction Stop
$disk = Get-Disk -Number $partition.DiskNumber -ErrorAction Stop
if ($partition.DiskNumber -ne $BackupDiskNumber) {
throw "Drive ${BackupDriveLetter}: is on Disk $($partition.DiskNumber), not requested Disk $BackupDiskNumber."
}
if ($disk.IsBoot -or $disk.IsSystem) {
throw "Drive ${BackupDriveLetter}: is backed by a boot or system disk. Refusing to continue."
}
if ($volume.FileSystemLabel -ne 'DCBackup') {
throw "Drive ${BackupDriveLetter}: has label '$($volume.FileSystemLabel)', not 'DCBackup'. Refusing to continue."
}
}
Assert-Elevated
Import-Module ActiveDirectory
Import-Module ServerManager
$domain = Get-ADDomain
if ($domain.DNSRoot -ne $DomainFqdn) {
throw "Connected domain '$($domain.DNSRoot)' does not match requested domain '$DomainFqdn'."
}
if ($domain.PDCEmulator -ne "$env:COMPUTERNAME.$DomainFqdn") {
throw "Run the time configuration on the PDC Emulator '$($domain.PDCEmulator)'."
}
if ($BackupDriveLetter.Length -ne 1 -or $BackupDriveLetter -notmatch '^[A-Za-z]$') {
throw 'BackupDriveLetter must be one alphabetic character.'
}
Assert-ExistingBackupTargetSafe
Write-Output '=== Current State ==='
Get-RecoveryState | Format-List | Out-String | Write-Output
if ($ValidateOnly) {
Write-Output 'Validation mode only. No recovery or time configuration was changed.'
return
}
$recycleBin = Get-ADOptionalFeature -Identity 'Recycle Bin Feature'
if ($recycleBin.EnabledScopes.Count -eq 0) {
Enable-ADOptionalFeature -Identity 'Recycle Bin Feature' -Scope ForestOrConfigurationSet -Target $DomainFqdn -Confirm:$false
}
if (-not (Get-WindowsFeature Windows-Server-Backup).Installed) {
Install-WindowsFeature Windows-Server-Backup | Out-Null
}
$backupVolume = Get-Volume -ErrorAction Stop | Where-Object DriveLetter -eq $BackupDriveLetter
if (-not $backupVolume) {
$backupDisk = Get-Disk -Number $BackupDiskNumber -ErrorAction Stop
if ($backupDisk.IsBoot -or $backupDisk.IsSystem) {
throw "Disk $BackupDiskNumber is a boot or system disk. Refusing to modify it."
}
if ($backupDisk.PartitionStyle -ne 'RAW') {
throw "Disk $BackupDiskNumber is '$($backupDisk.PartitionStyle)', not RAW. Refusing to modify it."
}
$partition = $backupDisk |
Initialize-Disk -PartitionStyle GPT -PassThru |
New-Partition -DriveLetter $BackupDriveLetter -UseMaximumSize
Format-Volume -Partition $partition -FileSystem NTFS -NewFileSystemLabel 'DCBackup' -Confirm:$false | Out-Null
}
$peerList = $NtpPeers -join ' '
w32tm /config /manualpeerlist:"$peerList" /syncfromflags:manual /reliable:yes /update | Out-Null
Restart-Service W32Time -Force
Start-Sleep -Seconds 5
w32tm /resync /rediscover | Out-Null
if ($StartSystemStateBackup) {
wbadmin start systemstatebackup -backupTarget:"${BackupDriveLetter}:" -quiet
if ($LASTEXITCODE -ne 0) { throw "wbadmin failed with exit code $LASTEXITCODE." }
}
Write-Output '=== Result ==='
Get-RecoveryState | Format-List | Out-String | Write-Output
if ($StartSystemStateBackup) {
Write-Output '=== Backup Versions ==='
wbadmin get versions
}
Run the read-only inspection first:
Apply Recycle Bin, backup feature/disk preparation, and NTP configuration:
Start the first System State backup and wait for it to complete:
Do not launch a second backup while wbadmin or wbengine is active. Observe progress when needed:
wbadmin get status
Get-Process wbadmin,wbengine -ErrorAction SilentlyContinue
Get-Volume -DriveLetter E
Observed lab result:
- the first backup ran from
20:52:19through21:08:50local event time (about 16 minutes) - the 40 GB volume had approximately 29.7 GB free after completion
- use those figures only as lab evidence, not as universal production sizing; size retention from the real directory, policy, and recovery objectives
Validation
$feature = Get-ADOptionalFeature -Identity 'Recycle Bin Feature'
$feature.EnabledScopes.Count -gt 0
Get-WindowsFeature Windows-Server-Backup
Get-Disk -Number 1
Get-Volume -DriveLetter E
w32tm /query /peers
w32tm /query /source
w32tm /query /status
wbadmin get versions
Get-Service W32Time
Pass only when:
- Recycle Bin returns
True - backup feature is installed
E:isDCBackupon the dedicated disk- time source is one of the configured external peers
wbadmin get versionsreturns at least one completed System State version
Validation boundary:
- this runbook proves creation and catalog availability of a System State recovery point
- it does not prove authoritative restore, non-authoritative restore, DSRM access, or bare-metal recovery
- restoration remains a separate disruptive validation requiring an isolated recovery exercise
Evidence
qm config 4011showing the dedicatedscsi1- disk/volume output identifying non-system Disk
1andE:\DCBackup - Recycle Bin enabled scopes
- NTP peers, source, status, and W32Time service state
- successful Windows Backup event and
wbadmin get versions
Rollback
- AD Recycle Bin cannot be disabled after enablement.
- Correct NTP peers by rerunning the script with the approved
NtpPeersvalues. - Do not detach or format the backup disk after a recovery point exists unless retention and replacement are explicitly approved.
- Never use this runbook to restore AD; use an isolated recovery procedure.