Active Directory domain controller migration requires systematic planning and precise execution to maintain directory service availability during infrastructure transitions. This comprehensive guide covers domain controller deployment, FSMO role transfers, SYSVOL migration from FRS to DFSR, and production-ready decommissioning procedures.

Domain Controller Migration Planning

Migration Prerequisites

# Verify current environment health
# Check forest and domain functional levels
Get-ADForest | Select-Object Name, ForestMode
Get-ADDomain | Select-Object Name, DomainMode

# List all domain controllers
Get-ADDomainController -Filter * | Select-Object Name, IPv4Address, OperatingSystem, Site

# Identify FSMO role holders
$domain = Get-ADDomain
$forest = Get-ADForest

Write-Host "Domain FSMO Roles:" -ForegroundColor Yellow
Write-Host "PDC Emulator: $($domain.PDCEmulator)"
Write-Host "RID Master: $($domain.RIDMaster)"
Write-Host "Infrastructure Master: $($domain.InfrastructureMaster)"

Write-Host "`nForest FSMO Roles:" -ForegroundColor Yellow
Write-Host "Schema Master: $($forest.SchemaMaster)"
Write-Host "Domain Naming Master: $($forest.DomainNamingMaster)"

# Check replication health
repadmin /replsummary
repadmin /showrepl

# Verify SYSVOL replication state
dfsrmig /getglobalstate
dfsrmig /getmigrationstate

# Check DNS health
dcdiag /test:dns /v

SYSVOL Migration from FRS to DFSR

FRS to DFSR Migration Process

SYSVOL migration transitions from File Replication Service to DFS Replication:

# Migration states:
# State 0: Start (FRS)
# State 1: Prepared (FRS and DFSR, FRS is authoritative)
# State 2: Redirected (FRS and DFSR, DFSR is authoritative)
# State 3: Eliminated (DFSR only)

# Check current SYSVOL replication state
dfsrmig /getglobalstate

# Verify domain and forest functional levels (must be Windows Server 2008 or higher)
$domain = Get-ADDomain
$forest = Get-ADForest

if ($domain.DomainMode -lt 'Windows2008Domain' -or $forest.ForestMode -lt 'Windows2008Forest') {
    Write-Error "Domain/Forest functional level must be Windows Server 2008 or higher"
    exit
}

# Stage 1: Prepare migration
dfsrmig /setglobalstate 1

# Wait for all DCs to reach Prepared state
do {
    Start-Sleep -Seconds 60
    $state = dfsrmig /getmigrationstate
    Write-Host "Checking migration state..." -ForegroundColor Cyan
    $state
} until ($state -match "All Domain Controllers have migrated successfully")

# Verify DFSR SYSVOL folder created
Get-ChildItem "C:\Windows\SYSVOL\domain" -Force

# Stage 2: Redirect to DFSR
dfsrmig /setglobalstate 2

# Wait for all DCs to reach Redirected state
do {
    Start-Sleep -Seconds 60
    $state = dfsrmig /getmigrationstate
    Write-Host "Checking migration state..." -ForegroundColor Cyan
    $state
} until ($state -match "All Domain Controllers have migrated successfully")

# Verify SYSVOL share is now using DFSR path
Get-SmbShare | Where-Object Name -like "*SYSVOL*" | Select-Object Name, Path

# Stage 3: Eliminate FRS
dfsrmig /setglobalstate 3

# Wait for all DCs to reach Eliminated state
do {
    Start-Sleep -Seconds 60
    $state = dfsrmig /getmigrationstate
    Write-Host "Checking migration state..." -ForegroundColor Cyan
    $state
} until ($state -match "All Domain Controllers have migrated successfully")

# Verify FRS service is stopped
Get-Service -Name NTFRS | Select-Object Name, Status, StartType

# Final verification
dfsrmig /getglobalstate
# Should show: Current DFSR global state: 'Eliminated'

SYSVOL Replication Troubleshooting

# Check DFSR replication status
Get-DfsrBacklog -GroupName "Domain System Volume" -FolderName "SYSVOL Share" -SourceComputerName DC01 -DestinationComputerName DC02

# Verify DFSR health
dfsrdiag /testdfsrconfig /member:DC01
dfsrdiag /testdfsrinteg /member:DC01

# Force SYSVOL replication
dfsrdiag pollad
dfsrdiag syncnow /partner:DC02 /RGName:"Domain System Volume" /Time:1

# View DFSR replication reports
Get-DfsrConnectionSchedule -GroupName "Domain System Volume"
Get-DfsrMembership | Where-Object GroupName -eq "Domain System Volume" | Format-Table -AutoSize

# Rebuild SYSVOL if corrupted (CRITICAL: Last resort only)
# Stop DFSR service
Stop-Service -Name DFSR -Force

# Set authoritative restore
wmic /namespace:\\root\microsoftdfs path dfsrVolumeConfig where volumeGuid="GUID" call ResumeReplication

# Restart DFSR service
Start-Service -Name DFSR

New Domain Controller Deployment

Installing Active Directory Domain Services

# Install AD DS role on new server
Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools

# Import AD DS deployment module
Import-Module ADDSDeployment

# Promote to domain controller (additional DC in existing domain)
$domainName = "corp.contoso.com"
$safeModePassword = Read-Host -AsSecureString -Prompt "Enter Safe Mode Administrator Password"
$domainCred = Get-Credential -Message "Enter Domain Admin credentials"

Install-ADDSDomainController `
    -DomainName $domainName `
    -Credential $domainCred `
    -SafeModeAdministratorPassword $safeModePassword `
    -SiteName "Default-First-Site-Name" `
    -InstallDns:$true `
    -CreateDnsDelegation:$false `
    -DatabasePath "C:\Windows\NTDS" `
    -LogPath "C:\Windows\NTDS" `
    -SysvolPath "C:\Windows\SYSVOL" `
    -NoRebootOnCompletion:$false `
    -Force:$true

# Server will reboot automatically
# After reboot, verify domain controller functionality
dcdiag /v
dcdiag /test:replications

Post-Deployment Verification

# Verify domain controller is operational
Get-ADDomainController -Identity $env:COMPUTERNAME | Select-Object Name, IPv4Address, OperatingSystem, IsGlobalCatalog, Site

# Check Active Directory services
Get-Service -Name NTDS, DNS, Netlogon, W32Time, DFSR | Select-Object Name, Status, StartType

# Verify DNS registration
nslookup $env:COMPUTERNAME
nslookup _ldap._tcp.dc._msdcs.corp.contoso.com

# Test authentication
nltest /sc_query:corp.contoso.com

# Verify replication
repadmin /replsum
repadmin /syncall /AdeP

# Check SYSVOL share
Get-SmbShare | Where-Object Name -like "*SYSVOL*" | Select-Object Name, Path
Get-ChildItem "C:\Windows\SYSVOL\domain\Policies" -Recurse

FSMO Role Transfer

Graceful FSMO Role Transfer

# Transfer all FSMO roles to new DC (DC02)
$newDC = "DC02.corp.contoso.com"

# Transfer PDC Emulator
Move-ADDirectoryServerOperationMasterRole -Identity $newDC -OperationMasterRole PDCEmulator -Confirm:$false

# Transfer RID Master
Move-ADDirectoryServerOperationMasterRole -Identity $newDC -OperationMasterRole RIDMaster -Confirm:$false

# Transfer Infrastructure Master
Move-ADDirectoryServerOperationMasterRole -Identity $newDC -OperationMasterRole InfrastructureMaster -Confirm:$false

# Transfer Schema Master
Move-ADDirectoryServerOperationMasterRole -Identity $newDC -OperationMasterRole SchemaMaster -Confirm:$false

# Transfer Domain Naming Master
Move-ADDirectoryServerOperationMasterRole -Identity $newDC -OperationMasterRole DomainNamingMaster -Confirm:$false

# Transfer all roles in single command
Move-ADDirectoryServerOperationMasterRole -Identity $newDC -OperationMasterRole PDCEmulator,RIDMaster,InfrastructureMaster,SchemaMaster,DomainNamingMaster -Confirm:$false

# Verify new role holders
Get-ADDomain | Select-Object PDCEmulator, RIDMaster, InfrastructureMaster
Get-ADForest | Select-Object SchemaMaster, DomainNamingMaster

# Using netdom (alternative method)
netdom query fsmo

FSMO Seizure (Emergency Only)

# CRITICAL: Only use if original DC is permanently offline
# Run on server that will seize roles

# Enter ntdsutil
ntdsutil

# Seize roles
roles
connections
connect to server DC02
quit

# Seize PDC Emulator
seize pdc
# Confirm: Yes

# Seize RID Master
seize rid master
# Confirm: Yes

# Seize Infrastructure Master
seize infrastructure master
# Confirm: Yes

# Seize Schema Master
seize schema master
# Confirm: Yes

# Seize Domain Naming Master
seize naming master
# Confirm: Yes

quit
quit

# Verify seized roles
Get-ADDomain | Select-Object PDCEmulator, RIDMaster, InfrastructureMaster
Get-ADForest | Select-Object SchemaMaster, DomainNamingMaster

# IMPORTANT: After seizing roles, clean up metadata of failed DC
ntdsutil
metadata cleanup
connections
connect to server DC02
quit
select operation target
list domains
select domain 0
list sites
select site 0
list servers in site
select server 0  # Old DC
quit
remove selected server
quit
quit

Network Configuration Updates

DNS and DHCP Reconfiguration

# Update DNS server addresses on new DC
$adapter = Get-NetAdapter | Where-Object Status -eq 'Up' | Select-Object -First 1
Set-DnsClientServerAddress -InterfaceIndex $adapter.ifIndex -ServerAddresses ("127.0.0.1","10.0.1.11")

# Update DHCP scope options to point to new DC
# Old DC: 10.0.1.10
# New DC: 10.0.1.11

# Get DHCP server (run on DHCP server)
$dhcpServer = "DHCP01.corp.contoso.com"
$scopeId = "10.0.1.0"

# Update DNS servers in scope options
Set-DhcpServerv4OptionValue -ComputerName $dhcpServer -ScopeId $scopeId -OptionId 6 -Value @("10.0.1.11","10.0.1.12")

# Update domain name
Set-DhcpServerv4OptionValue -ComputerName $dhcpServer -ScopeId $scopeId -OptionId 15 -Value "corp.contoso.com"

# Verify DHCP options
Get-DhcpServerv4OptionValue -ComputerName $dhcpServer -ScopeId $scopeId

# Update static DNS entries
# Remove old DC from static configurations
# Add new DC to client DNS settings

Client Configuration Updates

# Update Group Policy to reference new DC
# GPO computer startup script
$script = @'
$adapter = Get-NetAdapter | Where-Object Status -eq 'Up' | Select-Object -First 1
Set-DnsClientServerAddress -InterfaceIndex $adapter.ifIndex -ServerAddresses ("10.0.1.11","10.0.1.12")
ipconfig /registerdns
'@

# Create GPO startup script
$gpoName = "Update DNS Servers"
New-GPO -Name $gpoName
Set-GPRegistryValue -Name $gpoName -Key "HKLM\Software\Policies\Microsoft\Windows\NetworkList\Signatures\Unmanaged" -ValueName "DNS" -Type String -Value "10.0.1.11"

# Link GPO to domain
New-GPLink -Name $gpoName -Target "DC=corp,DC=contoso,DC=com"

# Force Group Policy update on clients
Invoke-GPUpdate -Computer "CLIENT01" -Force

Old Domain Controller Decommissioning

Graceful Demotion Process

# Run on old DC (DC01) after FSMO transfer and metadata cleanup

# Verify no FSMO roles remain
Get-ADDomain | Select-Object PDCEmulator, RIDMaster, InfrastructureMaster
Get-ADForest | Select-Object SchemaMaster, DomainNamingMaster

# Verify replication is healthy
repadmin /replsum

# Demote domain controller
$localAdminPassword = Read-Host -AsSecureString -Prompt "Enter new local Administrator password"

Uninstall-ADDSDomainController `
    -DemoteOperationMasterRole:$true `
    -LocalAdministratorPassword $localAdminPassword `
    -RemoveDnsDelegation:$false `
    -Force:$true

# Server will reboot automatically
# After reboot, it becomes a member server

# Remove AD DS role
Uninstall-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools -Restart

# Remove from domain (optional - if retiring server)
Remove-Computer -UnjoinDomainCredential (Get-Credential) -PassThru -Verbose -Restart

Metadata Cleanup

# Run on remaining DC if old DC was forcibly removed
# Clean up Active Directory metadata

# Using PowerShell
$oldDC = "DC01"
Get-ADDomainController -Identity $oldDC | Remove-ADObject -Recursive -Confirm:$false

# Using ntdsutil (alternative method)
ntdsutil
metadata cleanup
connections
connect to server DC02
quit
select operation target
list domains
select domain 0
list sites
select site 0
list servers in site
select server 1  # Old DC (DC01)
quit
remove selected server
quit
quit

# Clean up DNS records
$zone = "corp.contoso.com"
$oldDCName = "DC01"

# Remove A records
Remove-DnsServerResourceRecord -ZoneName $zone -Name $oldDCName -RRType A -Force

# Remove SRV records
Get-DnsServerResourceRecord -ZoneName $zone | Where-Object {$_.RecordData.DomainName -like "*$oldDCName*"} | Remove-DnsServerResourceRecord -ZoneName $zone -Force

# Clean up old DC computer account
Get-ADComputer -Identity $oldDC | Remove-ADObject -Recursive -Confirm:$false

Verification and Testing

Post-Migration Validation

# Comprehensive validation script
function Test-DomainControllerMigration {
    $results = @()

    # Test 1: Domain controller count
    $dcCount = (Get-ADDomainController -Filter *).Count
    $results += [PSCustomObject]@{
        Test = "Domain Controller Count"
        Expected = "2"
        Actual = $dcCount
        Status = if ($dcCount -ge 2) { "Pass" } else { "Fail" }
    }

    # Test 2: FSMO role holders
    $domain = Get-ADDomain
    $forest = Get-ADForest
    $newDC = "DC02.corp.contoso.com"

    $fsmoCheck = $true
    if ($domain.PDCEmulator -ne $newDC) { $fsmoCheck = $false }
    if ($domain.RIDMaster -ne $newDC) { $fsmoCheck = $false }
    if ($domain.InfrastructureMaster -ne $newDC) { $fsmoCheck = $false }
    if ($forest.SchemaMaster -ne $newDC) { $fsmoCheck = $false }
    if ($forest.DomainNamingMaster -ne $newDC) { $fsmoCheck = $false }

    $results += [PSCustomObject]@{
        Test = "FSMO Roles on New DC"
        Expected = $newDC
        Actual = "PDC:$($domain.PDCEmulator)"
        Status = if ($fsmoCheck) { "Pass" } else { "Fail" }
    }

    # Test 3: Replication health
    $replErrors = (repadmin /showrepl 2>&1 | Select-String "error|fail").Count
    $results += [PSCustomObject]@{
        Test = "Replication Errors"
        Expected = "0"
        Actual = $replErrors
        Status = if ($replErrors -eq 0) { "Pass" } else { "Fail" }
    }

    # Test 4: SYSVOL replication state
    $sysvolState = dfsrmig /getglobalstate
    $results += [PSCustomObject]@{
        Test = "SYSVOL Migration State"
        Expected = "Eliminated"
        Actual = if ($sysvolState -match "Eliminated") { "Eliminated" } else { "Other" }
        Status = if ($sysvolState -match "Eliminated") { "Pass" } else { "Fail" }
    }

    # Test 5: DNS functionality
    $dnsTest = (Resolve-DnsName -Name $env:USERDNSDOMAIN -Type SRV -ErrorAction SilentlyContinue).Count
    $results += [PSCustomObject]@{
        Test = "DNS SRV Records"
        Expected = ">0"
        Actual = $dnsTest
        Status = if ($dnsTest -gt 0) { "Pass" } else { "Fail" }
    }

    # Test 6: Authentication
    $authTest = nltest /sc_query:$env:USERDNSDOMAIN 2>&1
    $results += [PSCustomObject]@{
        Test = "Domain Authentication"
        Expected = "Success"
        Actual = if ($authTest -match "success") { "Success" } else { "Failed" }
        Status = if ($authTest -match "success") { "Pass" } else { "Fail" }
    }

    return $results | Format-Table -AutoSize
}

# Run validation
Test-DomainControllerMigration

# Additional manual checks
dcdiag /v > C:\Logs\dcdiag-post-migration.txt
repadmin /showrepl > C:\Logs\replication-post-migration.txt

Backup and Disaster Recovery

Post-Migration Backups

# Perform system state backup of new DC
wbadmin start systemstatebackup -backupTarget:E: -quiet

# Verify backup
wbadmin get versions -backupTarget:E:

# Export AD configuration
repadmin /showrepl > C:\Backup\AD-Replication-$(Get-Date -Format 'yyyyMMdd').txt
dcdiag /v > C:\Backup\DCDiag-$(Get-Date -Format 'yyyyMMdd').txt

# Export Group Policy Objects
Backup-GPO -All -Path "C:\Backup\GPO-Backup-$(Get-Date -Format 'yyyyMMdd')"

# Document configuration
$report = @{
    Date = Get-Date
    DomainControllers = Get-ADDomainController -Filter * | Select-Object Name, IPv4Address, OperatingSystem, Site
    FSMORoles = @{
        PDC = (Get-ADDomain).PDCEmulator
        RID = (Get-ADDomain).RIDMaster
        Infrastructure = (Get-ADDomain).InfrastructureMaster
        Schema = (Get-ADForest).SchemaMaster
        DomainNaming = (Get-ADForest).DomainNamingMaster
    }
    ReplicationStatus = (repadmin /replsum 2>&1)
}

$report | ConvertTo-Json -Depth 10 | Out-File "C:\Backup\AD-Config-$(Get-Date -Format 'yyyyMMdd').json"

Conclusion

Active Directory domain controller migration ensures infrastructure modernization while maintaining directory service availability. The procedures detailed in this guide enable:

  • Zero-Downtime Migration: Seamless DC replacement without service interruption
  • SYSVOL Modernization: FRS to DFSR migration for improved replication
  • FSMO Role Management: Controlled transfer or emergency seizure procedures
  • Metadata Cleanup: Proper removal of decommissioned DC references
  • Comprehensive Validation: Systematic testing of post-migration environment

Always maintain comprehensive backups, validate replication health throughout the migration, and document each step for audit purposes. Test procedures in non-production environments and schedule maintenance windows for critical FSMO role transfers. Monitor Active Directory health for 48-72 hours post-migration to ensure stability.