Skip to content

Practical technology help for homes and small businesses, from someone who knows how to make it work. Based in Martinez, serving Contra Costa County.

Practical IT guides, cheatsheets, and references from Jeremiah Ellington, drawn from more than 20 years of IT work in public sector and higher education.

Contact Info
Location Martinez, CA (Serving Contra Costa County)
Contact Info
Location Martinez, CA (Serving Contra Costa County)

Active Directory

Domain Controller Migration Runbook: Add New DCs and Retire Old Ones

A ten-phase checklist for adding new Windows Server domain controllers to an existing Active Directory domain, moving the FSMO roles, and retiring the old DCs safely.

  • By Jeremiah Ellington
  • Updated
  • Last reviewed
  • 10 min read

Who this is for

Administrators who already run an Active Directory domain and need to replace its domain controllers with new servers, one at a time, without downtime.

Before you start

  • Domain Admins membership, and Enterprise Admins for the forest-wide FSMO roles and the automatic schema update
  • A current, tested system-state backup of at least two existing DCs
  • A maintenance window and a written rollback plan for each phase
  • The new servers' names, static IPv4 addresses and AD site, decided in advance

Applies to

Adding Windows Server 2022 or 2025 domain controllers to an existing single-domain Active Directory forest, then demoting the older DCs. Commands for Windows PowerShell 5.1 with the ActiveDirectory, ADDSDeployment, DnsServer and DhcpServer modules. Checked against Microsoft Learn on 2026-10-26; not tested on hardware.

Ask AI about this guideChatGPT, Claude, or any assistant

These open a new chat with a prompt that points the assistant to this guide. It only sees the guide if it can open the link. If it says it can't, use Copy guide for AI and paste the text into the chat.

Nothing goes to an AI service unless you choose one. AI answers can be wrong: check them against the guide before you change anything important.

This runbook is for replacing the domain controllers in an Active Directory domain you already run. You add new DCs alongside the old ones, prove they're healthy, move the FSMO roles, repoint everything that used the old DCs, and only then demote the old ones. Done in that order, nobody should notice.

It doesn't cover building a new forest from nothing, an in-place OS upgrade of an existing DC, read-only DCs, or multi-domain forests. Every name and address below is a made-up example: corp.example.com and addresses from the documentation ranges in RFC 5737. Swap in your own before you run anything.

Before you start#

New forest or existing domain?#

These are different jobs, and mixing their commands is a classic way to break things.

You're doingCmdletThis runbook?
Building a brand-new forest (first DC of a new domain)Install-ADDSForestNo. That creates a new, separate directory.
Adding a DC to a domain that already existsInstall-ADDSDomainControllerYes
Removing a DC that isn't the last one in its domainUninstall-ADDSDomainControllerYes

Example names used on this page#

PlaceholderMeaningExample
corp.example.comYour AD DNS domain (also the forest root here)corp.example.com
DC=corp,DC=example,DC=comThe same domain as a distinguished name
<OldDC>A DC you're retiring (repeat per DC)DC-OLD-01 at 192.0.2.10
<NewDC>A new DC you're adding (repeat per DC)DC-NEW-01 at 192.0.2.20
<Site>The AD site the new DC belongs toDefault-First-Site-Name
<Gateway>The subnet's default gateway192.0.2.1

How to read the steps#

  • Where to run it is in each code block's title. "Elevated" means an administrator Windows PowerShell 5.1 session. Some cmdlets used here (Add-Computer, Test-ComputerSecureChannel) aren't in PowerShell 7.
  • Steps tagged Changes production in the checklists change directory, DNS, DHCP or server state. Each has a caution above it and, where the cmdlet supports it, a -WhatIf or test run first.
  • Only commands checked against Microsoft's documentation appear in copyable code blocks. Emergency procedures (seizing roles, metadata cleanup) are described in text on purpose: read the linked article before you do either.
  • Nothing on this page runs anything. Your ticks and notes stay in your browser, and they're only saved if you turn saving on above.

Phase 1: Health baseline and safety net#

Record a known-good state before you change anything, and make sure you can get back to it. If the domain isn't healthy now, fix that first: a new DC copies whatever problems the old ones have.

PowerShellChanges production: On each <OldDC>, elevated: system-state backup to a dedicated volume
Install-WindowsFeature Windows-Server-Backup
wbadmin start systemstatebackup -backupTarget:E:
PowerShellOn each <OldDC>, elevated: full diagnostics saved to a file
New-Item -ItemType Directory -Path C:\Migration -ErrorAction SilentlyContinue
dcdiag /v /c /s:<OldDC> /f:C:\Migration\dcdiag_<OldDC>_baseline.txt
dcdiag /test:DNS /v /s:<OldDC>
dcdiag /test:Advertising /test:NetLogons /test:SysVolCheck /test:DFSREvent /s:<OldDC>
PowerShellFrom any domain-joined admin host, elevated: replication summary
repadmin /replsummary
repadmin /showrepl * /csv > C:\Migration\showrepl_baseline.csv
repadmin /queue
PowerShellOn the PDC emulator, elevated: SYSVOL replication state
dfsrmig /getglobalstate

dfsrmig /getglobalstate should report the Eliminated state, which means SYSVOL already replicates with DFS Replication. Windows Server 2019 and later can't be added as DCs while the domain still uses FRS for SYSVOL. If yours does, migrate first with Microsoft's SYSVOL migration guide, and treat that as its own change: moving to Eliminated can't be undone.

PowerShellFrom an admin host with the ActiveDirectory module: inventory and levels
Get-ADDomainController -Filter * | Select-Object Name,IPv4Address,Site,OperationMasterRoles
Get-ADForest | Select-Object Name,ForestMode
Get-ADDomain | Select-Object DNSRoot,DomainMode
Get-SmbShare -CimSession <OldDC> -Name SYSVOL,NETLOGON
w32tm /monitor

Check the functional levels against the new DCs' OS. Per Microsoft's functional-level table, a Windows Server 2025 DC needs domain and forest functional levels of at least Windows Server 2016. Earlier releases accept some lower levels, so look up your exact combination in that table. If your levels are too low for the release you want, plan an intermediate step.

Phase 1 checklist

Phase 2: Build and patch the new servers#

Build each new server with a supported Windows Server release, give it its final name, and patch it fully before it joins the domain. Server Core is a good fit for a DC.

PowerShellOn each <NewDC>, elevated
Rename-Computer -NewName <NewDC> -Restart

Patch with whatever your organization already uses (WSUS, your update management tool, or Windows Update). On Server Core, sconfig option 6 (Install updates) installs quality updates. Repeat until no updates are offered, then reboot.

Set the time zone if it isn't right (Get-TimeZone -ListAvailable lists the IDs). Don't configure a separate time source on a DC that isn't the PDC emulator: members of the domain follow the domain hierarchy.

PowerShellOn each <NewDC>, elevated
Set-TimeZone -Id "<Time zone ID>"
Phase 2 checklist

Phase 3: Static IP, DNS client and domain join#

Point each new server at the existing DCs for DNS before it joins, so the join resolves the domain correctly.

PowerShellOn each <NewDC>, elevated (example: 192.0.2.20/24)
New-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress 192.0.2.20 -PrefixLength 24 -DefaultGateway 192.0.2.1
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses 192.0.2.10,192.0.2.11

Adding a static address this way turns DHCP off on that interface. Run it at the console or through out-of-band access: if you're connected over the old address, you'll lose the session.

PowerShellOn each <NewDC>, elevated, Windows PowerShell 5.1
Add-Computer -DomainName "corp.example.com" -Credential (Get-Credential) -Restart
PowerShellOn each <NewDC> after the reboot (still a member server)
Test-ComputerSecureChannel -Verbose
nltest /dsgetdc:corp.example.com
Phase 3 checklist

Phase 4: Install AD DS and promote, one server at a time#

Promote one server, let it replicate cleanly, and only then start the next. Run the prerequisite test with the same parameters first: it changes nothing and tells you what would fail.

PowerShellOn each <NewDC>, elevated
Install-WindowsFeature AD-Domain-Services,DNS -IncludeManagementTools
Import-Module ADDSDeployment
Test-ADDSDomainControllerInstallation -DomainName "corp.example.com" -SiteName "<Site>" -InstallDns:$true -Credential (Get-Credential) -SafeModeAdministratorPassword (Read-Host -AsSecureString "DSRM password")
PowerShellChanges production: on the same <NewDC>, elevated: promote (prompts before it reboots)
Install-ADDSDomainController -DomainName "corp.example.com" -SiteName "<Site>" -InstallDns:$true -Credential (Get-Credential) -SafeModeAdministratorPassword (Read-Host -AsSecureString "DSRM password")

The new DC is a global catalog by default. Store the DSRM password the way you store other break-glass credentials: you'll need it for a directory restore.

Phase 4 checklist

Phase 5: Validate replication#

Confirm each new DC is a healthy replication partner before you move on.

PowerShellFrom an admin host, elevated: against each <NewDC>
dcdiag /v /s:<NewDC>
repadmin /showrepl <NewDC>
repadmin /replsummary
repadmin /kcc <NewDC>
Get-ADReplicationPartnerMetadata -Target <NewDC> -Scope Server | Format-Table Partner,LastReplicationSuccess,LastReplicationResult -AutoSize

If you need to push a change out quickly, repadmin /syncall <NewDC> /AdeP synchronizes all partitions across all sites, pushing from that DC. It's safe, but it generates replication traffic across every site link.

Phase 5 checklist

Phase 6: Confirm SYSVOL and NETLOGON#

A DC can finish promotion but not yet share SYSVOL. Until it does, it can't hand out Group Policy or logon scripts, so check for this explicitly.

PowerShellFrom an admin host, elevated: against each <NewDC>
Get-SmbShare -CimSession <NewDC> -Name SYSVOL,NETLOGON
Test-Path "\\<NewDC>\SYSVOL"
Test-Path "\\<NewDC>\NETLOGON"
dcdiag /test:NetLogons /test:SysVolCheck /test:DFSREvent /s:<NewDC>
PowerShellFrom a host with the DFS Management tools (RSAT-DFS-Mgmt-Con)
Get-DfsrState -ComputerName <NewDC>
Phase 6 checklist

Phase 7: Find and repoint everything that uses the old DCs#

Do this before you move roles or demote anything. The usual surprises are DHCP's DNS option, DHCP relay on routers, static DNS settings on servers, LDAP binds in applications, RADIUS, backup software and monitoring.

PowerShellOn each DHCP server, elevated: read the DNS server option (6)
Export-DhcpServer -File C:\Migration\dhcp-before.xml -Leases
Get-DhcpServerv4OptionValue -OptionId 6
Get-DhcpServerv4Scope | ForEach-Object { Get-DhcpServerv4OptionValue -ScopeId $_.ScopeId -OptionId 6 -ErrorAction SilentlyContinue }
PowerShellChanges production: on each DHCP server, elevated: set the server-level DNS option (validates the servers)
Set-DhcpServerv4OptionValue -DnsServer 192.0.2.20,192.0.2.21 -WhatIf
Set-DhcpServerv4OptionValue -DnsServer 192.0.2.20,192.0.2.21

For each scope that sets its own option 6 (the read step above lists them), set it on the scope too:

PowerShellChanges production: on each DHCP server, elevated: set the DNS option on one scope (example scope 192.0.2.0)
Set-DhcpServerv4OptionValue -ScopeId 192.0.2.0 -DnsServer 192.0.2.20,192.0.2.21 -WhatIf
Set-DhcpServerv4OptionValue -ScopeId 192.0.2.0 -DnsServer 192.0.2.20,192.0.2.21

On routers and layer-3 switches, look for DHCP relay (helper) addresses that point at an old DC that also runs DHCP. Add the new relay address before you remove the old one, and save the configuration. The syntax depends on the vendor and OS version, so follow your platform's documentation.

PowerShellFrom an admin host: look for hard-coded names and addresses (example values)
Get-ChildItem -Path C:\Scripts -Recurse -Include *.ps1,*.psm1,*.config,*.ini | Select-String -SimpleMatch -Pattern "DC-OLD-01","192.0.2.10"
Get-DnsClientServerAddress -CimSession <host>
Resolve-DnsName corp.example.com -Type NS

For applications that bind to LDAP, check each one's settings for a DC name or address. Test LDAP and LDAPS reachability on each new DC (this only tests the TCP port, not the certificate):

PowerShellFrom an application server
389,636 | ForEach-Object { Test-NetConnection -ComputerName <NewDC> -Port $_ }
PowerShellOn each <NewDC>: a certificate for LDAPS that names this DC
Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.DnsNameList.Unicode -contains "<NewDC>.corp.example.com" }

On an NPS server, Get-NpsRadiusClient lists the RADIUS clients (switches, wireless controllers, VPN) that send authentication there. NPS itself finds DCs through the domain, but check any client that was configured with an old DC's address directly.

Phase 7 checklist

Phase 8: Transfer the FSMO roles#

Move all five operation master roles onto new DCs while the current holders are online. That's a transfer, the safe path, as long as you don't add -Force. Moving forest-wide roles (schema master, domain naming master) needs Enterprise Admins; the domain roles need Domain Admins.

PowerShellOn any DC, elevated: current role holders
netdom query fsmo
PowerShellChanges production: from an admin host, elevated: graceful transfer (preview, then transfer; prompts to confirm)
Move-ADDirectoryServerOperationMasterRole -Identity "<NewDC>" -OperationMasterRole SchemaMaster,DomainNamingMaster,PDCEmulator,RIDMaster,InfrastructureMaster -WhatIf
Move-ADDirectoryServerOperationMasterRole -Identity "<NewDC>" -OperationMasterRole SchemaMaster,DomainNamingMaster,PDCEmulator,RIDMaster,InfrastructureMaster
netdom query fsmo

You can split the roles across new DCs if that suits your sites. If not every DC is a global catalog and the AD Recycle Bin is off, keep the infrastructure master off a global catalog server. Once the PDC emulator moves, configure the new holder's external time source, and set the old one back to the domain hierarchy.

Phase 8 checklist

Phase 9: Demote the old DCs, one at a time#

Demote one old DC, confirm the domain is still healthy, then do the next. Run the uninstall test first.

Before the first demotion, repoint each new DC's own DNS client. Phase 3 pointed the new DCs at the old DCs (192.0.2.10, 192.0.2.11) so they could join the domain. If they still point only there, they lose name resolution when the old DCs go. List another new DC first and the DC's own address last:

PowerShellChanges production: on DC-NEW-01 (192.0.2.20), elevated: other new DC first, then itself
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses 192.0.2.21,192.0.2.20
Get-DnsClientServerAddress -InterfaceAlias "Ethernet" -AddressFamily IPv4

Microsoft's DNS client recommendations say that after any change to a DC's DNS client settings you clear the resolver cache and register its DNS records. ipconfig /flushdns only empties this server's local resolver cache; it changes nothing on any DNS server. ipconfig /registerdns starts a dynamic registration of this server's DNS names and IP addresses, so it writes to the live zone.

PowerShellChanges production: on the same new DC, elevated: clear the local cache, then re-register its DNS records
ipconfig /flushdns
ipconfig /registerdns

Do the same on each new DC with its own addresses. Some admins use the loopback address (127.0.0.1) as the last entry instead of the DC's own address. Whichever you choose, test name resolution and a reboot on a test domain first: it hasn't been tested for this page.

PowerShellChanges production: on the <OldDC> being retired, elevated (each prompts for a new local Administrator password)
Import-Module ADDSDeployment
Test-ADDSDomainControllerUninstallation -Credential (Get-Credential)
Uninstall-ADDSDomainController -Credential (Get-Credential)

After it reboots as a member server, remove the roles it no longer needs. If it also runs DHCP or file shares, leave those until they've moved.

PowerShellChanges production: on the same server after the reboot, elevated (restarts it)
Uninstall-WindowsFeature AD-Domain-Services,DNS -WhatIf
Uninstall-WindowsFeature AD-Domain-Services,DNS -Restart
PowerShellFrom an admin host: confirm it's gone before starting the next one
Get-ADDomainController -Filter * | Select-Object Name,Site
repadmin /replsummary

If an old DC is dead and can't demote itself, don't just leave it powered off: its metadata keeps it in the replication topology. Clean it up as described in Microsoft's metadata cleanup article. Deleting the DC's computer object in Active Directory Users and Computers does the cleanup; in Sites and Services, delete the NTDS Settings object before the server object.

Phase 9 checklist

Phase 10: Clean up DNS and AD, then final checks#

A clean demotion removes most of what it should. Look for leftovers, and remove them only after you've confirmed what they are.

PowerShellOn a new DC, elevated: find records still naming an old DC (read-only)
Get-DnsServerResourceRecord -ZoneName "corp.example.com" | Where-Object { $_.HostName -like "*DC-OLD-01*" -or $_.RecordData.NameServer -like "DC-OLD-01.*" -or $_.RecordData.DomainName -like "DC-OLD-01.*" -or $_.RecordData.IPv4Address.IPAddressToString -eq "192.0.2.10" }
Get-DnsServerResourceRecord -ZoneName "_msdcs.corp.example.com" | Where-Object { $_.RecordData.HostNameAlias -like "DC-OLD-01.*" -or $_.RecordData.NameServer -like "DC-OLD-01.*" -or $_.RecordData.DomainName -like "DC-OLD-01.*" }
Get-ADObject -SearchBase "CN=Sites,CN=Configuration,DC=corp,DC=example,DC=com" -Filter 'Name -eq "DC-OLD-01"'
PowerShellChanges production: on a new DC, elevated: remove one confirmed leftover, the old DC's address on the same-as-parent record (preview, then remove)
Remove-DnsServerResourceRecord -ZoneName "corp.example.com" -Name "@" -RRType A -RecordData 192.0.2.10 -WhatIf
Remove-DnsServerResourceRecord -ZoneName "corp.example.com" -Name "@" -RRType A -RecordData 192.0.2.10

The demoted server's object under Sites and Services usually stays behind as an empty server object. Delete it in Active Directory Sites and Services once it has no NTDS Settings child.

Lingering objects are a separate problem, usually after a DC was offline longer than the tombstone lifetime. If replication logs event 1388 or 1988, see Microsoft's guidance on repadmin /removelingeringobjects, and run it with /advisory_mode first.

PowerShellFrom a client that gets its address by DHCP, at the console: final checks
nltest /sc_query:corp.example.com
Resolve-DnsName corp.example.com -Type NS -Server <NewDC>
ipconfig /all
389,636,88,445 | ForEach-Object { Test-NetConnection -ComputerName <NewDC> -Port $_ }

Renew the client's DHCP lease from its own console (renewing over a remote session drops it), then check ipconfig /all shows only the new DNS servers.

Once the old DCs are gone and stable, you can raise the domain and forest functional levels. Treat that as its own planned change: Microsoft describes raises as generally irreversible.

Phase 10 checklist

Next steps#

Keep the dependency list: it's the start of documentation for the next migration. Put the new DCs in monitoring and backups, and schedule a test restore.

Sources and official documentation

Review history

  • Technical review: Jeremiah Ellington,
  • Editorial review: Jeremiah Ellington,
  • Next scheduled review:

Spotted something out of date or wrong? Email a correction and I'll fix it. See how these guides are made.

Written by Jeremiah Ellington

Jeremiah has spent more than 20 years in IT: running help desks, managing networks, firewalls, and servers, and leading infrastructure projects for public-sector and university organizations. He runs Ellington Technologies, a part-time, owner-operated IT business in Martinez, California.