Windows Server for beginners. Part 20: How do you back up and restore Active Directory?
All parts of the series “Windows Server for beginners”A directory with four controllers has built-in protection against losing one of them: the others hold exactly the same data, and in the previous part we saw that a dead controller is easier to replace than to restore. But replication protects against losing a controller, not against losing data. An OU with five hundred users deleted by mistake is deleted on every controller of the site within seconds, and everywhere with the next replication between sites; a schema extended with the wrong file is extended in the whole forest; ransomware that gets hold of a domain admin account gets to every controller. Only a copy that lives outside the directory protects against that, together with the skill to restore exactly what is needed from it.
The commands below run from the admin workstation ws1 in PowerShell 7 (part 15); whatever has to run on the controller itself (wbadmin, ntdsutil, logs, the registry) goes through Invoke-Command (part 14) or the controller's console when it is booted into restore mode. The domain is corp.example.com with four controllers: dc1 and dc2 in the Office site, dc3 and dc4 in the Branch site, dc1 is the PDC.
What to back up
For Windows, a controller backup is the system state: boot files, the registry together with the COM+ registration, SYSVOL, the directory database ntds.dit with its transaction logs (C:\Windows\NTDS), and, if the server hosts a certification authority, IIS or a cluster, their database, metabase and configuration. AD-integrated DNS zones live in the directory database and get into the backup with it; file-based zones (System32\dns\*.dns) are not part of the system state and are backed up with their volume.
The database isn't copied as files. Windows takes a snapshot of the volume through the VSS (Volume Shadow Copy Service): applications that have their own VSS writer pause writing for a moment and bring their data to a consistent state, the snapshot is fixed, and the backup is read from it. The directory service has such a writer (NTDS): it hands over the database and logs in a consistent state and, after a successful backup, records a mark of it in the directory. A copy of ntds.dit taken without VSS — Copy-Item from a running controller, a copy of the virtual disk file on the fly — is a database in the middle of a transaction, and you can't restore from it.
The backup mark is the dSASignature attribute on the root of each partition. It replicates, so any controller shows when and by which controller a partition was last backed up: that's what repadmin /showbackup displays (the output is at the end of this part). Once a day each controller compares the age of this mark with a threshold and, if a partition hasn't been backed up for longer, logs warning 2089 in the Directory Service log — one per such partition, every day, until a backup is made. The threshold is the registry value Backup Latency Threshold (days) under HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters; by default it is half the tombstone lifetime, that is 90 days with 180. The help of repadmin /?:showbackup advises setting it to 1 day in production, Microsoft's article about the event suggests getting it every other day without a backup. The value is set on each controller separately, and it has a flip side: a large value simply silences the warning, and that is the only way the directory could remind you that there is no backup.
What and how often:
| What | With what | How often |
|---|---|---|
| System state of at least two controllers, including one in each domain | Windows Server Backup or a product that supports the NTDS VSS writer | daily; keep longer than the interval between checks, but shorter than the tombstone lifetime: a backup older than 180 days can't be restored |
| DHCP database | Backup-DhcpServer or Export-DhcpServer (part 8) |
daily, to another place; the server itself puts a copy into System32\dhcp\backup every 60 minutes, but on the same disk |
| Group Policy | Backup-GPO -All -Path |
after every change; the subject of part 24 |
| Certification authority: database, key, templates | Backup-CARoleService |
after every change; part 25 |
| File-based DNS zones, if any | a copy of the volume or of the System32\dns\*.dns files |
together with the system state |
| DSRM password of each controller and passwords of the emergency accounts | a password manager outside the domain | on every change |
The last row matters most: a restore starts with logging into restore mode with the DSRM password from part 4, and if that password lives in a password manager that authenticates through the same domain, there will be no one to restore.
And one rule about storage: the backup must live where a domain admin can't reach it. Ransomware works with their rights, and a backup on a network share that Domain Admins can access gets encrypted together with the controllers. A separate account for backups, storage with immutable snapshots or simply a disk you disconnect — any of these is better than a shared folder.
Windows Server Backup
The built-in tool is the Windows-Server-Backup feature: a service, a console, the wbadmin utility and the WindowsServerBackup module. It isn't installed by default, and until it is, there is no wbadmin on the server either:
PS C:\> $dcs = (Get-ADDomainController -Filter *).HostName
PS C:\> Invoke-Command $dcs { Get-WindowsFeature Windows-Server-Backup } | Sort-Object PSComputerName | Format-Table PSComputerName, Name, InstallState
PSComputerName Name InstallState
-------------- ---- ------------
dc1.corp.example.com Windows-Server-Backup Available
dc2.corp.example.com Windows-Server-Backup Available
dc3.corp.example.com Windows-Server-Backup Available
dc4.corp.example.com Windows-Server-Backup Available
Available means the feature is available but not installed. We install it on dc2 and make a one-time system state backup to a separate disk E::
PS C:\> Invoke-Command dc2 { Install-WindowsFeature Windows-Server-Backup }
PS C:\> Invoke-Command dc2 { wbadmin start systemstatebackup -backupTarget:E: -quiet }
wbadmin creates a shadow copy of the volumes that hold system state files and writes the backup to E:\WindowsImageBackup\<computer name>\; -quiet removes the "continue?" prompt. By default the target volume can't be a **critical** one — a volume that holds any file of the system state (usually C:); the registry value AllowSSBToAnyVolume under HKLM\SYSTEM\CurrentControlSet\Services\wbengine\SystemStateBackup allows it, but a backup on the same disk as the database survives only a logical error, not the loss of the disk. Instead of a volume you can specify a network share (-backupTarget:\\server\share), but Windows Server Backup keeps no versions there: the next backup of the same server to the same folder overwrites the previous one, and if it fails, none is left.
A schedule is set through a module policy:
PS C:\> Invoke-Command dc2 {
$policy = New-WBPolicy
Add-WBSystemState -Policy $policy
Add-WBBackupTarget -Policy $policy -Target (New-WBBackupTarget -VolumePath E:)
Set-WBSchedule -Policy $policy -Schedule 02:00
Set-WBPolicy -Policy $policy -Force
}
New-WBPolicy creates an empty policy, Add-WBSystemState adds the system state to it, New-WBBackupTarget -VolumePath defines the volume for backups, Set-WBSchedule the time of the daily run (several, comma-separated, are allowed), and Set-WBPolicy makes the policy active. Get-WBSummary (the last successful backup and the next scheduled one) and wbadmin get versions (the list of backups) show the result.
Add-WBBareMetalRecovery instead of Add-WBSystemState adds everything needed to restore the server onto bare metal or an empty virtual machine: the system volume and the boot partitions in full; the system state alone can be restored from such a backup too. For the only controller of a domain it is a must; for a controller that has partners, the system state is enough, because the server itself is easier to reinstall.
Commercial products do the same through the same VSS writer; when choosing one, a single word in its description matters — application-aware (or "with VSS support for Active Directory"). A backup of the whole virtual machine without it is exactly that copy of the disk on the fly: the NTDS VSS writer doesn't know about it, dSASignature doesn't change, and 2089 keeps coming.
The Recycle Bin
The first scenario is deleted objects, and it is covered without a backup if the AD Recycle Bin is enabled, as in part 5. Enabling it can't be undone (the feature's IsDisableable is False), and EnabledScopes shows that it applies to the whole forest — on every controller and in the partitions object:
PS C:\> (Get-ADOptionalFeature 'Recycle Bin Feature').EnabledScopes
CN=NTDS Settings,CN=DC4,CN=Servers,CN=Branch,CN=Sites,CN=Configuration,DC=corp,DC=example,DC=com
CN=NTDS Settings,CN=DC3,CN=Servers,CN=Branch,CN=Sites,CN=Configuration,DC=corp,DC=example,DC=com
CN=NTDS Settings,CN=DC1,CN=Servers,CN=Office,CN=Sites,CN=Configuration,DC=corp,DC=example,DC=com
CN=NTDS Settings,CN=DC2,CN=Servers,CN=Office,CN=Sites,CN=Configuration,DC=corp,DC=example,DC=com
CN=Partitions,CN=Configuration,DC=corp,DC=example,DC=com
A deleted object keeps all its attributes, including links (group memberships, manager), the SID and the password, for the period msDS-DeletedObjectLifetime. Usually nobody sets it in a forest, and then it equals the tombstone lifetime:
PS C:\> Get-ADObject "CN=Directory Service,CN=Windows NT,CN=Services,$((Get-ADRootDSE).configurationNamingContext)" -Properties tombstoneLifetime, 'msDS-DeletedObjectLifetime' | Format-List tombstoneLifetime, msDS-DeletedObjectLifetime
tombstoneLifetime : 180
msDS-DeletedObjectLifetime :
The scenario: someone deleted the OU Departments as a whole, with everything inside — the nested OUs Sales and Branch, users, groups and a gMSA account. In the Deleted Objects container it looks like this:
PS C:\> $t = Get-Date '2026-10-26 02:00'
PS C:\> Get-ADObject -SearchBase (Get-ADDomain).DeletedObjectsContainer -Filter 'whenChanged -ge $t' -IncludeDeletedObjects -Properties msDS-LastKnownRDN, lastKnownParent |
Format-Table ObjectClass, msDS-LastKnownRDN, @{n='Parent'; e={($_.lastKnownParent -split ',')[0]}}
ObjectClass msDS-LastKnownRDN Parent
----------- ----------------- ------
organizationalUnit Departments DC=corp
organizationalUnit Sales OU=Departments\0ADEL:7c1d5e2a-4b3f-4e8d-9a61-0f2b8c7d3e15
organizationalUnit Branch OU=Departments\0ADEL:7c1d5e2a-4b3f-4e8d-9a61-0f2b8c7d3e15
user Alice Smith OU=Sales\0ADEL:2e5a8f14-9c3b-4d7a-b6e0-5f1c3a9d8b27
user Bob Jones OU=Sales\0ADEL:2e5a8f14-9c3b-4d7a-b6e0-5f1c3a9d8b27
group sales OU=Departments\0ADEL:7c1d5e2a-4b3f-4e8d-9a61-0f2b8c7d3e15
group branch-admins OU=Departments\0ADEL:7c1d5e2a-4b3f-4e8d-9a61-0f2b8c7d3e15
user Carol White OU=Sales\0ADEL:2e5a8f14-9c3b-4d7a-b6e0-5f1c3a9d8b27
user Erin Brown OU=Branch\0ADEL:b83d2c6f-1e4a-4f9b-8c75-d2a6e0f4b913
container Printers OU=Branch\0ADEL:b83d2c6f-1e4a-4f9b-8c75-d2a6e0f4b913
msDS-GroupManagedServiceAccount web OU=Departments\0ADEL:7c1d5e2a-4b3f-4e8d-9a61-0f2b8c7d3e15
msDS-LastKnownRDN is the object's former name, lastKnownParent is where it lived. Only Departments itself has a live parent (DC=corp,…); for all the others lastKnownParent points to a deleted parent in Deleted Objects. This isn't a string written at the moment of deletion: lastKnownParent, like any DN attribute, stores a reference to an object and shows its current DN. While the parent is deleted, that is a DN with \0ADEL:<GUID>; as soon as the parent is restored, the children show its live DN there.
Hence the restore order — top down, because Restore-ADObject puts an object back into lastKnownParent, and the parent must exist by then:
PS C:\> Get-ADObject -Filter 'msDS-LastKnownRDN -eq "Departments"' -IncludeDeletedObjects | Restore-ADObject
PS C:\> Get-ADObject -Filter 'lastKnownParent -eq "OU=Departments,DC=corp,DC=example,DC=com"' -IncludeDeletedObjects | Restore-ADObject
PS C:\> Get-ADObject -Filter 'lastKnownParent -eq "OU=Sales,OU=Departments,DC=corp,DC=example,DC=com"' -IncludeDeletedObjects | Restore-ADObject
PS C:\> Get-ADObject -Filter 'lastKnownParent -eq "OU=Branch,OU=Departments,DC=corp,DC=example,DC=com"' -IncludeDeletedObjects | Restore-ADObject
Each next line finds the children by the live DN of the parent just restored. Restore-ADObject outputs nothing (with -PassThru, the restored object), and -TargetPath and -NewName put the object into another place or under another name.
Searching for the children while the parent is still deleted won't work with -Filter: the DN of a deleted parent contains \0A, and the module's filter doesn't find such an object. An LDAP filter does, if the backslash is escaped as \5C:
PS C:\> $ou = Get-ADObject -Filter 'msDS-LastKnownRDN -eq "Departments"' -IncludeDeletedObjects
PS C:\> Get-ADObject -Filter "lastKnownParent -eq '$($ou.DistinguishedName)'" -IncludeDeletedObjects | Measure-Object | Select-Object Count
Count
-----
0
PS C:\> Get-ADObject -LDAPFilter "(lastKnownParent=$($ou.DistinguishedName -replace '\\', '\5C'))" -IncludeDeletedObjects -Properties msDS-LastKnownRDN |
Format-Table ObjectClass, msDS-LastKnownRDN
ObjectClass msDS-LastKnownRDN
----------- -----------------
organizationalUnit Sales
organizationalUnit Branch
group sales
group branch-admins
msDS-GroupManagedServiceAccount web
What the Recycle Bin keeps for a deleted user:
PS C:\> Get-ADObject -Filter 'msDS-LastKnownRDN -eq "Carol White"' -IncludeDeletedObjects -Properties * |
Format-List Name, isDeleted, isRecycled, lastKnownParent, objectSid, memberOf, sAMAccountName
Name : Carol White
DEL:9f8e7d6c-5b4a-4c3d-8e2f-1a0b9c8d7e6f
isDeleted : True
isRecycled :
lastKnownParent : OU=Sales\0ADEL:2e5a8f14-9c3b-4d7a-b6e0-5f1c3a9d8b27,CN=Deleted Objects,DC=corp,DC=example,DC=com
objectSid : S-1-5-21-3623811015-3361044348-30300820-1108
memberOf : {CN=sales\0ADEL:6a1f3e9d-2c8b-4b7e-a5d4-3e9f1c2b8a70,CN=Deleted Objects,DC=corp,DC=example,DC=com}
sAMAccountName : cwhite
The SID is there, and so is the membership: memberOf shows the sales group, which itself sits in the Recycle Bin, and once both are restored the link comes back to life. isRecycled is empty — the object can still be restored. When msDS-DeletedObjectLifetime runs out, the object becomes recycled: most of its attributes are stripped, like a tombstone in a forest without the Recycle Bin, and the Recycle Bin can't restore it anymore — the only way back is a backup.
What the Recycle Bin doesn't do: it doesn't keep objects longer than that period; it doesn't restore attributes changed on a live object (a wrongly edited member of a group isn't a deletion); and it doesn't help if it was enabled after the deletion. For those cases there is the backup.
Nonauthoritative restore
The second scenario: a controller is lost or damaged, its partners are alive. Restoring the system state returns the controller to its state at the time of the backup, after which it catches up from its partners with everything that changed since. The backup is considered less current than the partners — hence "nonauthoritative". With such a restore the directory gets a new invocationID, and the USN rollback from part 18 doesn't happen: for the partners this is a new source of changes.
The procedure runs in Directory Services Restore Mode (DSRM): the controller boots as an ordinary server without the directory service, the database lies there as files, and it can be replaced. You get there not with F8 at boot but through the boot configuration — that way the controller also won't accidentally reboot into normal mode in the middle of the work:
PS C:\> bcdedit /set safeboot dsrepair
PS C:\> Restart-Computer
You log on with the local account .\Administrator and the DSRM password. Then, on the controller's console:
PS C:\> wbadmin get versions -backupTarget:E: -machine:dc2
PS C:\> wbadmin start systemstaterecovery -version:10/15/2026-00:00 -backupTarget:E: -machine:dc2 -quiet
PS C:\> bcdedit /deletevalue safeboot
PS C:\> Restart-Computer
wbadmin get versions lists the backups with their version identifiers in the form MM/DD/YYYY-HH:MM; -machine is required together with -backupTarget when one disk holds backups of several servers. Without -quiet, wbadmin asks twice: whether to proceed and whether the SYSVOL replication engine has stayed the same since the backup. SYSVOL is restored nonauthoritatively as well: the controller takes it from its partners (on the -authsysvol switch — below).
After a normal boot the Directory Service log shows event 1109:
The invocationID attribute for this directory server has been changed. The highest update sequence number at the time the backup was created is as follows:
Further on, the event lists the old and new invocationID and the USN at the time of the backup, and the explanation says when the invocationID changes: a restore from backup, applying a virtual machine snapshot, importing the machine. Then comes replication from the partners and the check from part 4.
When to do it and when not: a restore makes sense if the controller is the only one or holds something that takes long to set up again (DHCP, certificates, applications that don't belong there). A controller with partners and nothing special is faster to reinstall and promote again — from IFM media (Install From Media: a copy of the database taken with ntdsutil ifm on a live controller, so that the whole database doesn't travel over the network) or simply over the network. The result is the same, with fewer places to make a mistake.
Authoritative restore
The third scenario: objects are deleted on all controllers, there is no Recycle Bin or its period has run out, but there is a backup. A nonauthoritative restore returns the objects to one controller — and replication deletes them right away again: the partners remember the deletion, and it is newer. The restored objects have to become authoritative: their attribute version numbers must be raised so that they win in the conflict resolution from part 10.
ntdsutil does this on a stopped database: in DSRM, right after the nonauthoritative restore and before the reboot. If there is a controller the deletion hasn't reached yet, you can do without a backup: disable its inbound replication (repadmin /options <controller> +DISABLE_INBOUND_REPL), stop the NTDS service and mark the objects right there. With the service running, ntdsutil won't attach to the database:
PS C:\> Invoke-Command dc2 { ntdsutil "activate instance ntds" "authoritative restore" quit }
C:\WINDOWS\system32\ntdsutil.exe: activate instance ntds
Active instance set to "ntds".
C:\WINDOWS\system32\ntdsutil.exe: authoritative restore
Service "NTDS" is running. Stop the service before binding to this Active Directory database.
C:\WINDOWS\system32\ntdsutil.exe: quit
In DSRM the service isn't running, and the sequence is:
PS C:\> ntdsutil
ntdsutil: activate instance ntds
ntdsutil: authoritative restore
authoritative restore: restore subtree "OU=Sales,OU=Departments,DC=corp,DC=example,DC=com"
ntdsutil asks for confirmation in a dialog box (in a script it is turned off with popups off). The end of the output in the documentation looks like this (file names with our date and domain):
Successfully updated 3 records.
The following text file with a list of authoritatively restored
objects has been created in the current working directory:
ar_20261015-193512_objects.txt
One or more specified objects have back-links in this domain. The
following LDIF files with link restore operations have been created
in the current working directory:
ar_20261015-193512_links_corp.example.com.ldf
Authoritative Restore completed successfully.
According to the documentation, the version of every attribute of every object in the subtree is raised by 100,000 for each day since the backup (verinc <number> at the end of the command replaces 100,000 with another value — needed when the same backup is restored authoritatively a second time). No change made on other controllers in that time has accumulated that many versions, and the restored attributes win. They win entirely: if someone changed a phone number or a password of one of the objects after the backup, that change loses — the password goes back to its value at the time of the backup, and people need to be warned about that. On the other hand, attributes and values that weren't in the backup are kept: a user added to a restored group after the backup doesn't disappear from it.
restore object "<DN>" instead of restore subtree marks a single object; the documentation advises picking the lowest possible level of the tree so as not to roll back what has nothing to do with the deletion. Marking the whole database authoritative isn't possible in ntdsutil for Windows Server 2008 and later: such a rollback is no longer a restore of objects but a forest recovery (below).
After that — a reboot into normal mode and the order from Microsoft's article on restoring deleted users and groups: the controller is temporarily disconnected from the network, its inbound replication is disabled so that the partners don't get to send the deletion, the network is connected back, and the restored objects are pushed out:
PS C:\> repadmin /options dc2 +DISABLE_INBOUND_REPL
PS C:\> repadmin /syncall /d /e /P dc2 DC=corp,DC=example,DC=com
/syncall with /P (push) sends the changes from dc2 to its partners, /e across all sites, /d with names instead of GUIDs in the output.
The line about back-links in the ntdsutil output is what makes an authoritative restore harder than it looks. A user's group membership is stored in the group's member (the forward link), while the user's memberOf (the back-link) is computed from it and doesn't replicate. In forests with the Windows Server 2003 functional level or higher, each member value replicates separately (LVR, linked-value replication), and ntdsutil also raises the versions of the links to the restored objects — the membership comes back by itself. But the replication order can lose it, so the documentation advises applying the LDIF file in any case (LDAP Data Interchange Format — a text file with operations on the directory) that ntdsutil created next to it:
PS C:\> ldifde -i -k -f ar_20261015-193512_links_corp.example.com.ldf
PS C:\> repadmin /options dc2 -DISABLE_INBOUND_REPL
-i is import, -k skips errors such as "the value already exists". For groups in other domains of the forest, an LDIF file is built in each of them separately from ar_…_objects.txt (create ldif file from in the same ntdsutil menu), and the global catalog doesn't store membership of domain local groups of other domains at all.
SYSVOL
The fourth scenario isn't the directory but files: SYSVOL on the controllers has diverged (after 2213 or 4012 from part 18, after someone edited policy files right on disk), or all controllers were restored at once and none can be the source. DFS-R has two modes for this. Their names come from the old File Replication Service (FRS) that DFS-R replaced: in FRS they were the values D2 and D4 of the BurFlags registry value, and they are still called that.
- D2 — nonauthoritative synchronization: "forget your copy and take the partner's". For a controller whose SYSVOL is wrong; the others are left alone.
- D4 — authoritative: "my copy is right, everyone else takes it from me". For one controller — as Microsoft recommends, the PDC, whose SYSVOL is usually the most recent; all the others then have to do D2, or there will be conflicts.
Both modes are attributes of the controller's SYSVOL subscription object in the directory: msDFSR-Enabled (whether the folder takes part in replication) and msDFSR-Options (1 means "I'm authoritative"). This is how they look normally:
PS C:\> Get-ADObject -LDAPFilter '(cn=SYSVOL Subscription)' -SearchBase (Get-ADDomain).DomainControllersContainer -Properties msDFSR-Enabled, msDFSR-Options |
Format-Table @{n='DC'; e={($_.DistinguishedName -split ',')[3]}}, msDFSR-Enabled, msDFSR-Options
DC msDFSR-Enabled msDFSR-Options
-- -------------- --------------
CN=DC2 True
CN=DC1 True
CN=DC3 True
CN=DC4 True
msDFSR-Options isn't set anywhere, replication is enabled everywhere. D2 for dc3 alone:
PS C:\> $sub = 'CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=DC3,OU=Domain Controllers,DC=corp,DC=example,DC=com'
PS C:\> Set-ADObject $sub -Replace @{ 'msDFSR-Enabled' = $false } -Server dc1
PS C:\> repadmin /syncall dc1 /APed
PS C:\> Invoke-Command dc3 { dfsrdiag pollad }
# wait for event 4114 in the DFS Replication log on dc3
PS C:\> Set-ADObject $sub -Replace @{ 'msDFSR-Enabled' = $true } -Server dc1
PS C:\> repadmin /syncall dc1 /APed
PS C:\> Invoke-Command dc3 { dfsrdiag pollad }
# wait for 4614, then 4604 on dc3
The change is written on dc1 and pushed from there right away to all controllers of the forest (/A all partitions, /P from dc1 to its partners, /e across other sites too, /d names instead of GUIDs in the output): DFS Replication on dc3 reads its configuration from the directory, and the change has to get there. dfsrdiag pollad makes the service re-read its configuration without waiting for the next poll. 4114 means "the folder is disabled", 4614 "initialized and waiting for the initial sync with a partner", 4604 "the initial sync with the partner is complete". Until 4604 appears on a controller, it doesn't publish SYSVOL, and clients don't take policies from it.
D4 is longer. The DFSR service is stopped on all controllers of the domain (and its startup type set to Manual so that it doesn't come up by itself); the authoritative one gets msDFSR-Enabled = FALSE and msDFSR-Options = 1, all the others msDFSR-Enabled = FALSE; AD is replicated and checked to have arrived everywhere. Then DFSR is started on the authoritative controller and you wait for 4114; it gets msDFSR-Enabled = TRUE, AD is replicated again, dfsrdiag pollad runs on it, and you wait for 4602 — "initialized, this member is the primary member". Only after that is DFSR started on the others (each logs 4114), msDFSR-Enabled is turned back on for them, dfsrdiag pollad runs, and each goes 4614 → 4604, taking the copy from the authoritative controller. Finally the DFSR startup type goes back to Automatic.
The same logic applies after restoring a controller from a backup: the restored SYSVOL is nonauthoritative by default (D2), and wbadmin start systemstaterecovery -authsysvol makes it authoritative (D4). An authoritative SYSVOL is needed only on the first controller of each domain restored during a forest recovery; on the others it causes exactly those conflicts.
Forest recovery
The fifth scenario is the one nobody wants: the directory is damaged or compromised on all controllers. A failed schema extension, ransomware, a malicious admin, a restore from a backup that turned out to be a backup of something already broken. Microsoft published a separate guide for it (Active Directory Forest Recovery Guide), and it is worth reading and rehearsing before you need it. Its phases are: identify the problem and make sure a forest recovery is really needed (it is the last option, not the first); decide which backups to restore from; perform the initial recovery in isolation; redeploy the remaining controllers; clean up DNS and applications.
The initial recovery is one writable controller per domain, starting with the forest root. For it the guide lists the steps; the main ones are:
- Restore from a backup taken before the incident, without connecting to the production network: nonauthoritatively for AD DS and authoritatively for SYSVOL (
-authsysvolor D4 after the restore). Check that the data is unaffected; otherwise, use another backup. - If the cause is a breach: reset the passwords of all administrative accounts (Enterprise Admins, Domain Admins, Schema Admins and the rest), re-create the gMSAs, and if needed the trust passwords and the passwords of all users.
- Seize the FSMO roles (part 17) and clean up the metadata of all other controllers of the domain (part 19).
- Check DNS on this controller: the service runs, the controller points its DNS client to itself, the records of the removed controllers are gone.
- Raise
rIDAvailablePoolby 100,000 — so that new accounts don't get RIDs already issued after the backup (along with the rights those SIDs still have on resources) — and invalidate the current RID pool. - Reset the computer account password of this controller twice and the
krbtgtpassword twice (part 6): thekrbtgtpassword history holds two values, and only the second reset pushes the pre-failure password out of it. - In a multi-domain forest, remove the global catalog from it: a GC from a backup newer than the backups of other domains brings lingering objects.
- Configure time on the PDC of the forest root domain.
Then the restored controllers are joined in a common isolated network, replication is checked (repadmin /replsum, dcdiag /v), a global catalog is added, new backups are taken — and only then are the remaining controllers installed from scratch. Why one per domain: what matters most in a forest recovery is a database untouched by whatever broke the forest, and checking one backup for that is easier than checking several; the other controllers get the data from it.
Snapshots and clones
A snapshot of a controller's virtual machine isn't a backup, and part 18 explained why: rolling back to a snapshot on a hypervisor without VM-GenerationID is a USN rollback. With VM-GenerationID (an identifier the hypervisor changes inside the virtual machine when a snapshot is applied or a copy is imported) the controller notices the rollback, takes a new invocationID, discards its current RID pool and synchronizes the directory and SYSVOL nonauthoritatively from its partners. The directory survives that, but changes made on this controller after the snapshot that hadn't reached the partners are lost forever, and everything that doesn't come back through replication (files, application databases, settings on the server itself) jumps into the past. Microsoft says plainly that safe snapshot restore replaces neither a system state backup nor the Recycle Bin. And you must not restore all controllers of a domain from snapshots at once: each declares its SYSVOL nonauthoritative and waits for an authoritative partner that doesn't exist — then D4 from the section above saves the day.
Hyper-V has two kinds of checkpoints. A standard checkpoint saves the disk and memory of the running machine, and the Hyper-V documentation explicitly warns that for systems replicating data between nodes, such as Active Directory, this is a source of inconsistency. A production checkpoint (the default) is taken from inside the guest through VSS, without memory, and after it is applied the machine is off and boots again. That makes the rollback cleaner but doesn't turn a snapshot into a backup: it lives on the same storage as the machine. A snapshot has one honest use — rolling back within an hour after a failed update, before any directory change has spread.
There are also snapshots of the database itself — ntdsutil snapshot. It is a VSS shadow copy of the volumes with the database and logs, taken without stopping the controller; it can be mounted and opened as a separate LDAP server with the dsamain utility to see what the directory looked like at the moment of the snapshot: what was in a deleted OU, what the permissions were, who was in a group. It is a tool for choosing what to restore, not a way to restore: the data in a mounted snapshot is read-only.
PS C:\> Invoke-Command dc2 { ntdsutil "activate instance ntds" snapshot "?" "list all" quit quit }
C:\WINDOWS\system32\ntdsutil.exe: activate instance ntds
Active instance set to "ntds".
C:\WINDOWS\system32\ntdsutil.exe: snapshot
snapshot: ?
? - Show this help information
Activate Instance %s - Set "NTDS" or a specific AD LDS instance
as the active instance.
Create - Create a snapshot
Delete %s - Delete snapshot with index or guid %s. Specify * to delete all snapshots
Help - Show this help information
List All - List snapshots
List Mounted - List mounted snapshots
Mount %s - Mount snapshot with index or guid %s
Quit - Return to the prior menu
Unmount %s - Unmount snapshot with index or guid %s. Specify * to unmount all mounted snapshots
snapshot: list all
No snapshots found.
snapshot: quit
C:\WINDOWS\system32\ntdsutil.exe: quit
There are no snapshots. The workflow according to the documentation: ntdsutil "activate instance ntds" snapshot create quit quit (the same command goes into a scheduled task), then mount <GUID> — the snapshot appears as a folder C:\$SNAP_<date>_VOLUMEC$\; then, on the same controller,
PS C:\> dsamain -dbpath 'C:\$SNAP_202610151800_VOLUMEC$\Windows\NTDS\ntds.dit' -ldapPort 51389
and while dsamain runs, the snapshot answers as an LDAP server on port 51389 (and the next three — LDAPS and the global catalog). You can read it with ldp.exe or with the module's cmdlets using -Server dc2:51389; by default only Domain Admins and Enterprise Admins have access. The other switches (-logpath, -allowUpgrade, -allowNonAdminAccess, the LDAPS and global catalog ports) are printed by dsamain /? itself. A snapshot contains all password hashes of the domain, so it must be kept as carefully as a backup.
What virtualization really gives you is cloning of controllers, since Windows Server 2012. Instead of installing and promoting a new controller, you copy the virtual machine of an existing one, and on first start the copy turns itself into a new controller with a new name, address, invocationID and account. The conditions: the PDC runs Windows Server 2012 or later and is available during cloning, the hypervisor supports VM-GenerationID, the source controller is a member of the Cloneable Domain Controllers group (empty by default) and has no programs and services whose compatibility with cloning the system doesn't know. Checking the last one:
PS C:\> Get-ADGroup 'Cloneable Domain Controllers' -Properties member | Format-List Name, GroupScope, member
Name : Cloneable Domain Controllers
GroupScope : Global
member : {}
PS C:\> $x = Invoke-Command dc2 { Get-ADDCCloningExcludedApplicationList }
PS C:\> $x | Group-Object Type | Format-Table Count, Name
Count Name
----- ----
6 Program
83 Service
4 WoW64Program
PS C:\> $x | Where-Object Name -in 'DHCPServer', 'NtFrs', 'LocalKdc', 'sshd' | Format-Table Name, Type
Name Type
---- ----
DHCPServer Service
LocalKdc Service
NtFrs Service
sshd Service
Ninety-three entries on a Windows Server 2025 controller with DNS, DHCP, OpenSSH and PowerShell 7. The list contains not only the DHCP role, OpenSSH from part 16 and PowerShell 7, but dozens of the OS's own built-in services (LocalKdc, NtFrs and others): the allow list built into the system doesn't know them. Cloning won't start until every such entry is removed from the server or added to CustomDCCloneAllowList.xml (Get-ADDCCloningExcludedApplicationList -GenerateXml creates it from the current list — deciding what is really safe to copy is up to the admin).
Next, on dc2 itself:
PS C:\> Add-ADGroupMember 'Cloneable Domain Controllers' -Members (Get-ADComputer dc2)
PS C:\> New-ADDCCloneConfigFile -CloneComputerName dc5 -Static -IPv4Address 192.168.1.12 -IPv4SubnetMask 255.255.255.0 -IPv4DefaultGateway 192.168.1.1 -IPv4DNSResolver 192.168.1.10 -SiteName Office
New-ADDCCloneConfigFile checks the conditions above and writes DCCloneConfig.xml to C:\Windows\NTDS. Then dc2 is shut down gracefully (a running controller can't be copied), its checkpoints are deleted, the machine is exported and the copy imported with a new ID; if the source had a static MAC address, the copy gets a different one. On start the hypervisor gives the copy a new VM-GenerationID, the directory finds DCCloneConfig.xml, creates the new controller's account through the PDC and promotes it from its own database. A few minutes later the domain has five controllers. It is the fastest way to add a controller, and it is also the reason why a controller's virtual machine image must be kept as carefully as a backup: the whole directory is in it.
Looking with our own eyes
When the directory was last backed up, from its own point of view:
PS C:\> repadmin /showbackup
Repadmin: running command /showbackup against full DC dc2.corp.example.com
Loc.USN Originating DSA Org.USN Org.Time/Date Ver Attribute
======= =============== ========= ============= === =========
DC=DomainDnsZones,DC=corp,DC=example,DC=com
12694 4a7e9c21-6b0d-4f3e-9a58-2c1d7e8b6f40 447603 2011-12-04 21:24:31 155 dSASignature
DC=ForestDnsZones,DC=corp,DC=example,DC=com
12618 4a7e9c21-6b0d-4f3e-9a58-2c1d7e8b6f40 447604 2011-12-04 21:24:31 155 dSASignature
CN=Schema,CN=Configuration,DC=corp,DC=example,DC=com
4101 4a7e9c21-6b0d-4f3e-9a58-2c1d7e8b6f40 447602 2011-12-04 21:24:31 155 dSASignature
CN=Configuration,DC=corp,DC=example,DC=com
8589 4a7e9c21-6b0d-4f3e-9a58-2c1d7e8b6f40 447601 2011-12-04 21:24:31 155 dSASignature
DC=corp,DC=example,DC=com
11899 4a7e9c21-6b0d-4f3e-9a58-2c1d7e8b6f40 447600 2011-12-04 21:24:31 155 dSASignature
The format is the same as with repadmin /showobjmeta: this is the replication metadata of the dSASignature attribute on the root of each of the five partitions. Org.Time/Date is when the last successful backup wrote it, Ver is how many times it changed, so roughly that many backups were made (155). Originating DSA is the controller the backup was made on; instead of a name there is a GUID here: repadmin found no controller in the forest with that invocationID — it has long been gone (or its database has been restored since and got a new one). In other words, in this forest the last backup was made almost fifteen years ago, on a controller that no longer exists.
Then why don't all controllers shout about it with event 2089:
PS C:\> Invoke-Command $dcs { Get-WinEvent -FilterHashtable @{LogName='Directory Service'; Id=2089} -ErrorAction SilentlyContinue | Measure-Object } | Sort-Object PSComputerName | Format-Table PSComputerName, Count
PSComputerName Count
-------------- -----
dc1.corp.example.com 0
dc2.corp.example.com 995
dc3.corp.example.com 0
dc4.corp.example.com 190
PS C:\> Invoke-Command $dcs { Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters' | Select-Object 'Backup Latency Threshold (days)' } | Sort-Object PSComputerName | Format-Table PSComputerName, 'Backup Latency Threshold (days)'
PSComputerName Backup Latency Threshold (days)
-------------- -------------------------------
dc1.corp.example.com 7300
dc2.corp.example.com 3650
dc3.corp.example.com 7300
dc4.corp.example.com
Exactly what the beginning of this part was about: on dc1 and dc3 someone once raised the threshold to 7300 days (twenty years), and they are silent; on dc2 to 3650, ten years have long passed, and it logs again; on dc4, added recently, there is no value, and half the tombstone lifetime applies. The number of events is how many fit into the log, five a day, one per partition. The event itself:
PS C:\> Invoke-Command dc4 { Get-WinEvent -FilterHashtable @{LogName='Directory Service'; Id=2089} -MaxEvents 1 } | Select-Object -ExpandProperty Message
This directory partition has not been backed up since at least the following number of days.
Directory partition:
DC=DomainDnsZones,DC=corp,DC=example,DC=com
'Backup latency interval' (days):
90
It is recommended that you take a backup as often as possible to recover from accidental loss of data. However if you haven't taken a backup since at least the 'backup latency interval' number of days, this message will be logged every day until a backup is taken. You can take a backup of any replica that holds this partition.
By default the 'Backup latency interval' is set to half the 'Tombstone Lifetime Interval'. If you want to change the default 'Backup latency interval', you could do so by adding the following registry key.
'Backup latency interval' (days) registry key:
System\CurrentControlSet\Services\NTDS\Parameters\Backup Latency Threshold (days)
One system state backup of any controller cures it: dSASignature of all its partitions is updated, replicates, and 2089 stops everywhere. After that the threshold overrides should be removed.
What an authoritative restore sees — the attribute metadata of the deleted Carol White on dc1:
PS C:\> $carol = Get-ADObject -Filter 'msDS-LastKnownRDN -eq "Carol White"' -IncludeDeletedObjects
PS C:\> repadmin /showobjmeta dc1 "<GUID=$($carol.ObjectGUID)>" | Select-String -CaseSensitive 'Ver Attribute| cn$|isDeleted| name$|unicodePwd|sAMAccountName$|lastKnownParent'
Loc.USN Originating DSA Org.USN Org.Time/Date Ver Attribute
56808235 Office\DC1 56808235 2026-10-26 02:21:55 4 cn
56808235 Office\DC1 56808235 2026-10-26 02:21:55 3 isDeleted
56808235 Office\DC1 56808235 2026-10-26 02:21:55 4 name
56808148 Office\DC1 56808148 2026-10-26 02:16:52 2 unicodePwd
56808146 Office\DC1 56808146 2026-10-26 02:16:52 1 sAMAccountName
56808207 Office\DC1 56808207 2026-10-26 02:18:53 1 lastKnownParent
repadmin /showobjmeta also accepts a deleted object if you give its GUID. A deletion is a change of attributes: isDeleted at version 3 (the object was deleted, restored from the Recycle Bin and deleted again), cn and name at version 4 — the rename to Carol White\0ADEL:…. These are the versions the partners see, and these are what a backup has to beat: an authoritative restore of a backup taken the day before would raise the version of isDeleted on this object to a little over 100,000, and the deletion would lose.
And SYSVOL through the eyes of DFS-R — how dc4, when it was added to the domain, got SYSVOL nonauthoritatively, the same way as with D2:
PS C:\> Invoke-Command dc4 {
foreach ($id in 4614, 4604) {
Get-WinEvent -FilterHashtable @{LogName='DFS Replication'; Id=$id} | Select-Object TimeCreated, Id, @{n='Partner'; e={$_.Properties[6].Value}}
}
} | Format-Table TimeCreated, Id, Partner
TimeCreated Id Partner
----------- -- -------
22.09.2026 19:32:01 4614 dc3.corp.example.com
22.09.2026 19:32:04 4604 dc3.corp.example.com
4614: the folder is initialized and waits for the initial sync; 4604 three seconds later: the sync with dc3 is complete, SYSVOL is published. The Partner field is computed inside Invoke-Command: events that come back from the server no longer carry values in Properties.
Sources
Backup
- wbadmin start systemstatebackup — system state backup, a volume or a network share as the target;
- wbadmin start backup — what the system state contains, critical volumes, a backup on a network share being overwritten;
- Known Issues for AD DS Backup and Recovery — file-based DNS zones aren't part of the system state,
AllowSSBToAnyVolume; - New-WBPolicy, New-WBBackupTarget, Set-WBSchedule, Set-WBPolicy, Add-WBBareMetalRecovery and Get-WBSummary — a backup schedule from the
WindowsServerBackupmodule; - NTDS Replication Event 2089 is logged —
dSASignature, event 2089 andBackup Latency Threshold (days); - Shelf life of a system-state backup of AD and Tombstone-Lifetime — why a backup older than the tombstone lifetime is no good;
- Backup-DhcpServer, Backup-GPO and Backup-CARoleService — backups of DHCP, Group Policy and the certification authority.
The Recycle Bin
- Enable Active Directory Recycle Bin — what a deleted object keeps, irreversibility, restore;
- Restore-ADObject —
lastKnownParent,msDS-LastKnownRDN,-TargetPathand-NewName; - MS-ADTS: Tombstone Lifetime and Deleted-Object Lifetime — an empty
msDS-DeletedObjectLifetimeequals the tombstone lifetime.
Restore
- Restart the domain controller in Directory Services Restore Mode —
bcdedit /set safeboot dsrepairand logging on with the DSRM password; - Restore AD DS from backup (nonauthoritative restore), wbadmin get versions and wbadmin start systemstaterecovery — nonauthoritative restore,
-machine,-authsysvol; - Performing Authoritative Restore of Active Directory Objects and Mark an object or objects as authoritative — the procedure, a stopped service instead of DSRM, LVR and back-links, a sample output,
verinc; - authoritative restore — the
ntdsutilsubcommands, 100,000 for each day since the backup; - Restore user accounts and groups in AD — the order with
+DISABLE_INBOUND_REPLandrepadmin /syncall /d /e /P, LDIF files; - Run an LDIF file to recover back-links —
ldifde -i -k -f.
SYSVOL and the forest
- Force synchronization for DFSR-replicated sysvol replication — D2 and D4,
msDFSR-Enabled,msDFSR-Options, events 4114, 4602, 4614, 4604; - Active Directory Forest Recovery Guide, Steps for restoring the forest and Perform initial recovery — the phases of a forest recovery and the steps for the first controller of a domain.
Snapshots and clones
- Safely virtualizing Active Directory Domain Services — USN rollback, VM-GenerationID, a snapshot doesn't replace a backup;
- Virtualized Domain Controller Deployment and Configuration — cloning conditions and steps,
CustomDCCloneAllowList.xml, restoring all controllers at once; - Get-ADDCCloningExcludedApplicationList and New-ADDCCloneConfigFile — the cloning cmdlets;
- Using checkpoints — standard and production checkpoints in Hyper-V;
- Active Directory Domain Services Database Mounting Tool Step-by-Step Guide —
ntdsutil snapshotanddsamain.
The operations block is over. The next three parts are about what lies beyond the boundary of a single domain: when you need several domains, when you need a second forest, and how two forests agree to trust each other.
Next — part 21: multiple domains and forests. A child domain versus a separate forest: what domains of one forest share and what can't be undone, the schema and Enterprise Admins as the boundary, when a second forest is really needed, and what creating a child domain and a new tree looks like with Install-ADDSDomain and Install-ADDSForest.
Only registered users can leave a comment.
Sign in or register to leave a comment.