Active Directory Replication Health Diagnostic Script - ToddMaxey/Technical-Documentation GitHub Wiki
This PowerShell script automates a comprehensive replication-health check for all Domain Controllers (including RODCs) in the domain. It uses built-in tools to collect detailed information and attempt basic remediation. Key components are:
- DCDiag: This Microsoft tool analyzes the state of domain controllers and reports problems dcdiag | Microsoft Learn. We use it (with specific tests like Replications, SYSVOL, DNS) to catch replication and DNS issues.
-
Repadmin: A built-in AD replication management tool that shows the replication topology and errors Repadmin -showrepl | Microsoft Learn. We run
repadmin /replsummary,/showrepl, and/showconnto find any failed inbound/outbound replications. -
DNS SRV checks: The script runs
nslookupon the_ldap._tcp.dc._msdcs.<Domain>SRV records. SRV records identify domain controllers (e.g. _ldap and _kerberos services) Verify that SRV Domain Name System (DNS) records have been created - Windows Server | Microsoft Learn Verify that SRV Domain Name System (DNS) records have been created - Windows Server | Microsoft Learn. Correct SRV records are critical for DC discovery. -
SYSVOL/DFSR checks: It verifies the existence of the
SYSVOLshare and checks the DFS Replication (DFSR) service status. For Windows Server 2008+ DCs, SYSVOL replication uses DFSR. (Optionally, one can generate a DFSR health report withWrite-DfsrHealthReportWrite-DfsrHealthReport (DFSR) | Microsoft Learn.)
The overall workflow per DC is: enumerate DCs, run diagnostics (dcdiag, repadmin, nslookup, share/service checks), identify issues, attempt remediation (restart NTDS/DFSR services, force replication), then re-check. All results (issues found, actions taken, final status, and suggestions if unresolved) are written to the console and to C:\Temp\AD_Replication_Report.txt.
-
Initialization: Import the ActiveDirectory module, prepare the output log file (
C:\Temp\AD_Replication_Report.txt), and define a logging function. -
Enumerate DCs: Use
Get-ADDomainController -Filter *to list all domain controllers (including RODCs). -
Diagnostics per DC: For each DC:
- Run DCDiag with replication/SYSVOL/DNS tests, capturing any warnings or errors.
- Run Repadmin commands:
-
/replsummaryto get an overview of replication failures, -
/showrepl /errorsonlyto list any failed inbound replication attempts, -
/showconnto list replication connection objects.
-
- Run nslookup on
_ldap._tcp.dc._msdcs.<Domain>to verify SRV records. Microsoft documentation shows usingnslookupthis way to check AD locator records Verify that SRV Domain Name System (DNS) records have been created - Windows Server | Microsoft Learn Verify that SRV Domain Name System (DNS) records have been created - Windows Server | Microsoft Learn. If the DC’s name is missing, we log a warning. - Check the SYSVOL share (via
Get-SmbShare -Name SYSVOL) on the DC. If missing, note an issue. - Check the DFSR service status. On modern DCs, SYSVOL uses DFSR; if the service is not running, that’s an issue. (FRS is deprecated on newer servers.)
-
Remediation: If any issues are detected:
- Attempt to restart the NTDS service on the target DC (to recover the AD DS engine).
- Attempt to restart DFSR service if it exists and was problematic.
- Force replication with
repadmin /syncall <DC> /AeP(sync all naming contexts, all sites, push changes) Repadmin -syncall | Microsoft Learn. - Wait briefly, then rerun
repadmin /showreplto see if errors are cleared.
-
Summary and Logging: For each DC, the script logs: issues found, actions taken, and final status (e.g. “resolved” or warnings if still failing). Unresolved issues are flagged with suggestions (e.g. check network, event logs, firewall). All output is timestamped, printed to the screen, and appended to
AD_Replication_Report.txt.
Below is the complete PowerShell script with section headings and inline comments for clarity. It uses only non-deprecated cmdlets and is compatible with Windows Server 2016, 2019, 2022 (current supported versions).
<#
.SYNOPSIS
Comprehensive AD replication health check script for all domain controllers.
.DESCRIPTION
Runs DCDiag, Repadmin, DNS, and SYSVOL/DFSR checks on each DC, attempts basic remediation,
and logs a detailed report per DC.
.NOTES
Run as Administrator on a Domain Controller. Requires the ActiveDirectory PowerShell module.
#>
# Section: Initialization (Imports, variables, helper functions)
Import-Module ActiveDirectory -ErrorAction Stop # AD module for Get-ADDomainController
# Prepare report file
$reportFile = 'C:\Temp\AD_Replication_Report.txt'
$reportDir = Split-Path $reportFile
If (!(Test-Path $reportDir) { New-Item -ItemType Directory -Path $reportDir -Force | Out-Null }
"========== AD Replication Health Report ==========" | Out-File -FilePath $reportFile -Force -Encoding UTF8
"Report generated: $(Get-Date)" | Out-File -FilePath $reportFile -Append -Encoding UTF8
# Logging function to output to host and file
function Log {
param[string]$text)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$line = "[$timestamp] $text"
Write-Host $line
Add-Content -Path $reportFile -Value $line
}
# Section: Get all Domain Controllers (including RODCs)
Log "Enumerating all Domain Controllers in the domain..."
try {
$DCs = Get-ADDomainController -Filter * | Select-Object -Property HostName,OperatingSystem,IsReadOnly
} catch {
Log "ERROR: Failed to retrieve domain controllers. Ensure AD module is loaded and you have privileges."
exit 1
}
# Section: Diagnostics per DC
foreach ($dc in $DCs) {
$dcName = $dc.HostName
Log "==================================================="
Log "Checking DC: $dcName (Read-Only: $($dc.IsReadOnly) - OS: $($dc.OperatingSystem)"
Log "---------------------------------------------------"
$issues = @() # collect issues for summary
# DCDiag replication and SYSVOL tests
Log "Running DCDiag tests (replication, SYSVOL, DNS) on $dcName..."
try {
$tests = 'Replications','SysVolCheck','DNS','Join','Advertising','KCC'
$args = "/s:$dcName /test:$($tests -join ',') /skip:DNSBasic /q"
$dcdiagOutput = & dcdiag.exe $args 2>&1
} catch {
$dcdiagOutput = $_.Exception.Message
}
Log "DCDiag output for $dcName:`n$dcdiagOutput"
# Parse DCDiag for failures/warnings
if ($dcdiagOutput -match '(FAILED|Error|WARNING)') {
$dcdiagOutput -split "`n" | ForEach-Object {
if ($_ -match 'FAILED|Error|WARNING') {
$issues += $_.Trim()
}
}
}
if ($issues.Count -gt 0) {
Log "DCDiag reported issues on $dcName:"
foreach ($issue in $issues) { Log " - $issue" }
} else {
Log "No errors in DCDiag tests for $dcName."
}
# Repadmin checks
Log "Running Repadmin /replsummary on $dcName..."
$replSummary = & repadmin.exe /replsummary $dcName 2>&1
Log "Repadmin /replsummary $dcName:`n$replSummary"
Log "Running Repadmin /showrepl (errors only) on $dcName..."
$showRepl = & repadmin.exe /showrepl $dcName /errorsonly 2>&1
Log "Repadmin /showrepl $dcName (errors only):`n$showRepl"
if ($showRepl -match '\w') {
$showRepl -split "`n" | Where-Object { $_ -and ($_ -notmatch '^$') } | ForEach-Object {
$issues += $_.Trim()
}
if ($showRepl.Trim() {
Log "Replication errors found on $dcName:"
$showRepl -split "`n" | Where-Object {$_ -ne ""} | ForEach-Object { Log " $_" }
} else {
Log "No replication errors reported by Repadmin on $dcName."
}
}
Log "Running Repadmin /showconn on $dcName..."
$showConn = & repadmin.exe /showconn $dcName 2>&1
Log "Repadmin /showconn $dcName:`n$showConn"
# DNS SRV record check
Log "Checking DNS SRV records for $dcName..."
try {
$domain = (Get-ADDomain -Server $dcName).DNSRoot
} catch {
$domain = (Get-ADForest -Server $dcName).Name
}
Log "Domain DNS name: $domain"
$srvQuery = "_ldap._tcp.dc._msdcs.$domain"
$nsResult = & nslookup -type=SRV $srvQuery 2>&1
Log "Nslookup for $srvQuery:`n$nsResult"
if ($nsResult -match [regex]::Escape($dcName) {
Log "Found SRV record for $dcName in DNS."
} else {
$issues += "Missing SRV record for $dcName"
Log "WARNING: SRV record for $dcName not found."
}
# SYSVOL share check
Log "Checking SYSVOL share on $dcName..."
try {
$sysvol = Invoke-Command -ComputerName $dcName -ScriptBlock { Get-SmbShare -Name SYSVOL -ErrorAction SilentlyContinue }
if ($sysvol) {
Log "SYSVOL share exists on $dcName."
} else {
$issues += "SYSVOL share missing on $dcName"
Log "WARNING: SYSVOL share not found on $dcName."
}
} catch {
$issues += "Failed to query SYSVOL share on $dcName"
Log "ERROR: Could not query SYSVOL share on $dcName."
}
# DFSR service check
Log "Checking DFSR service on $dcName..."
try {
$dfsrSvc = Invoke-Command -ComputerName $dcName -ScriptBlock { Get-Service -Name DFSR -ErrorAction SilentlyContinue }
} catch {
$dfsrSvc = $null
}
if ($dfsrSvc) {
if ($dfsrSvc.Status -ne 'Running') {
$issues += "DFSR service is $($dfsrSvc.Status) on $dcName"
Log "WARNING: DFSR service status on $dcName: $($dfsrSvc.Status)"
} else {
Log "DFSR service is running on $dcName."
}
} else {
Log "DFSR service not present on $dcName (may be using FRS)."
}
# Section: Remediation if issues detected
if ($issues.Count -gt 0) {
Log "Issues detected on $dcName. Attempting remediation..."
# Restart NTDS service if needed
Log "Checking NTDS (AD DS) service on $dcName..."
try {
$ntdsSvc = Invoke-Command -ComputerName $dcName -ScriptBlock { Get-Service -Name NTDS }
if ($ntdsSvc.Status -ne 'Running') {
Log "NTDS service is $($ntdsSvc.Status). Restarting..."
Invoke-Command -ComputerName $dcName -ScriptBlock { Restart-Service NTDS -Force } -ErrorAction SilentlyContinue
Log "NTDS service restart initiated on $dcName."
}
} catch {
Log "ERROR: Could not access NTDS service on $dcName."
}
# Restart DFSR if necessary
if ($dfsrSvc -and $dfsrSvc.Status -ne 'Running') {
Log "Attempting to start DFSR service on $dcName..."
Invoke-Command -ComputerName $dcName -ScriptBlock { Restart-Service DFSR -Force } -ErrorAction SilentlyContinue
Log "DFSR service restart initiated on $dcName."
}
# Force replication
Log "Forcing AD replication with repadmin /syncall on $dcName..."
try {
$syncRes = & repadmin.exe /syncall $dcName /AeP /d 2>&1
Log "Repadmin /syncall output:`n$syncRes"
} catch {
Log "ERROR: repadmin /syncall failed on $dcName."
}
Start-Sleep -Seconds 5 # brief pause
# Re-check replication status after remediation
Log "Re-checking replication on $dcName after remediation..."
$showReplAfter = & repadmin.exe /showrepl $dcName /errorsonly 2>&1
if ($showReplAfter.Trim() -eq "") {
Log "No replication errors found on $dcName after remediation."
$resolved = $true
} else {
$showReplAfter -split "`n" | Where-Object { $_ -and ($_ -notmatch '^$') } | ForEach-Object {
Log " $_"
}
$resolved = $false
}
# Final remediation status
if ($resolved) {
Log "SUCCESS: Replication issues resolved on $dcName."
} else {
Log "WARNING: Replication issues still exist on $dcName after remediation."
Log "Suggestion: Check network connectivity, DNS, firewall, and event logs manually."
}
} else {
Log "No issues detected on $dcName. Skipping remediation."
}
Log "Completed checks for $dcName.`n"
}
Log "========== End of AD Replication Health Report =========="Notes:
- Ensure you run this script with Domain Admin rights on a DC.
- The script uses
Invoke-Commandto query remote DC services/share; if WinRM is disabled, you may skip those checks or run the script locally on each DC. - The DFSR health report (not scripted above) can be generated with the
Write-DfsrHealthReportcmdlet for deeper SYSVOL diagnostics Write-DfsrHealthReport (DFSR) | Microsoft Learn if needed. - This script provides verbose logging; you can adjust which diagnostics to run or how aggressively to remediate as suits your environment.