PowerShell: Replicate All Domain Controllers Immediately

<#
Author: KimConnect.com
Version: 0.1

Purpose:
- After a change has been issued against a "logon server", that domain controller would have the latest revision of GPO replication version. Instead of waiting for synchronization to occur within scheduled time windows, it's often preferable to trigger replication manually so that the desired changes are propagated to all DCs pronto. This script will detect the logon server and set it as the "source" to push new changes toward all "destinations" (other DCs) in the forest on demand.

Usage:
- Run this script as a Workstation Administrator of any domain joined computer. There is no need to be logged into a Domain Controller as this program will automatically connect to all DCs during its execution.
- The session will prompt for a domain administrator credential and it will check whether the input is valid. It will not proceed until a valid domain admin account is provided.

Current limitations:
- There's no proxy detection as that will make the script longer than necessary
- The domain controllers are assumed to have WinRM enabled and no firewall blocking port 9585 & 9586. There's a script to enable WinRM on remote DCs, but that's out of scope as of this revision.
#>

# Adding the Prerequisite Active Directory Module
if (!(get-module -name "ActiveDirectory") ){
Add-WindowsFeature RSAT-AD-PowerShell | out-null;
import-module -name "ActiveDirectory" -DisableNameChecking | out-null;
}

# Active Directory Object Variables
$gpo="Install BToE" # <====< Change this variable!
$objectCN="OU=Lab,DC=corp,DC=com" # <====< Change this variable!
$source=$logonServer=((nltest /DSGETDC: |Select-String -Pattern 'DC:') -Replace "DC: \\*").Trim()
$realm=(Get-AdDomain).DistinguishedName
$domain=(Get-AdDomain).DNSRoot # or $domain=$env:userdnsdomain
$allDcs=(Get-ADDomainController -Filter *).Name
[Array]$destinations=$allDcs.Split(" ") -ne $source
$domainAdmins=(Get-ADGroupMember -Identity "Domain Admins" -Recursive | %{Get-ADUser -Identity $_.distinguishedName} | Where-Object {$_.Enabled -eq $True}).SamAccountName
$domainObject = "LDAP://" + $domain

# Check whether a given username matches the list of Domain Admins
function validateDomainAdmin{
param (
[string]$username
)
$matchedAdmin=$username -in $domainAdmins
if($matchedAdmin){
Write-Host "$username is a Domain Admin";
return $True;
}else{
Write-Host "$username not a Domain Admin.";
return $False;
}
}

function testCredential{
param (
[string]$username,
[string]$password
)
$plaintextPassword = (New-Object System.Management.Automation.PSCredential 'N/A',$providedPassword).GetNetworkCredential().Password
$domainBindTest = (New-Object System.DirectoryServices.DirectoryEntry($domainObject,$username,$plaintextPassword)).DistinguishedName
if ($domainBindTest){return $True;} else{Return $False;}
}

function obtainDomainAdminCred{
$global:cred=$False
do {
$providedID=Read-Host -Prompt 'Input a domain admin username'
if (validateDomainAdmin $providedID){
$providedPassword = Read-Host -assecurestring "Please enter the password"
#$providedPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
#$providedCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $providedID,$providedPassword
$goodCredential=testCredential -username $providedID -password $providedPassword
if($goodCredential){
"Domain Admin Credential validated!";
$global:cred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $providedID,$providedPassword;
#return $True;
}
else{
"Password doesn't match.";
$global:cred=$False;
#return $False;
}
}else{
"Try again..."
#return $False;
}
} until ($cred)
}

# Local function
function executeRemote ($x)
{
get-gpo -name $x
# Get-ADReplicationAttributeMetadata -Object $objectCN -Server $source
# repadmin /syncall $destination (Get-ADDomain).DistinguishedName /e /A | Out-Null;
# Get-ADReplicationPartnerMetadata -Target $domain -Scope Domain | Select-Object Server, LastReplicationSuccess
}

function runonRemoteServer($server){
Invoke-Command -computername $server -credential $cred -ScriptBlock {
param( $x, $importedFunc)

# Import the function from the variable inside parameters
[ScriptBlock]::Create($importedFunc).Invoke($x)

} -ArgumentList $gpo, ${function:executeRemote}
}

function replicateDCs{
obtainDomainAdminCred;
foreach ($destination in $destinations){
"Performing replication on $destination..."
Repadmin /replicate $destination $source $realm
runonRemoteServer $destination
"Waiting 10 seconds before moving to next node...`n`------------------------------------------------------"
Start-Sleep 10;
}
"Done."
}

replicateDCs;

Sample output:

PS C:\Windows\system32> replicateDCs;
Input a domain admin username: kimconnect
kimconnect is a Domain Admin
Please enter the password: ****************************************
Domain Admin Credential validated!
Performing replication on DC01...
DsReplicaSync() failed with status 8452 (0x2104):
The naming context is in the process of being removed or is not replicated from the specified server.

DisplayName : Install BToE
DomainName : corp.com
Owner : CORP\Domain Admins
Id : -e034-
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 6/21/2019 5:39:42 PM
ModificationTime : 7/17/2019 5:32:10 PM
UserVersion : AD Version: 0, SysVol Version: 0
ComputerVersion : AD Version: 0, SysVol Version: 0
WmiFilter :
PSComputerName : DC01

Waiting 10 seconds before moving to next node...
------------------------------------------------------
Performing replication on DC03...
Sync from dc02.corp.com to DC01 completed successfully.

DisplayName : Install BToE
DomainName : corp.com
Owner : CORP\Domain Admins
Id : -e034-
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 6/21/2019 5:39:42 PM
ModificationTime : 7/17/2019 5:32:10 PM
UserVersion : AD Version: 0, SysVol Version: 0
ComputerVersion : AD Version: 0, SysVol Version: 0
WmiFilter :
PSComputerName : DC03

Waiting 10 seconds before moving to next node...
------------------------------------------------------
Performing replication on DC04...
Sync from dc02.corp.com to DC01 completed successfully.

DisplayName : Install BToE
DomainName : corp.com
Owner : CORP\Domain Admins
Id : -e034-
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 6/21/2019 5:39:42 PM
ModificationTime : 7/17/2019 5:32:10 PM
UserVersion : AD Version: 0, SysVol Version: 0
ComputerVersion : AD Version: 0, SysVol Version: 0
WmiFilter :
PSComputerName : DC04

Waiting 10 seconds before moving to next node...
------------------------------------------------------
Performing replication on DC05...
DsReplicaSync() failed with status 8452 (0x2104):
The naming context is in the process of being removed or is not replicated from the specified server.

DisplayName : Install BToE
DomainName : corp.com
Owner : CORP\Domain Admins
Id : e034-
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 6/21/2019 5:39:42 PM
ModificationTime : 7/17/2019 5:32:10 PM
UserVersion : AD Version: 0, SysVol Version: 0
ComputerVersion : AD Version: 0, SysVol Version: 0
WmiFilter :
PSComputerName : DC05

Waiting 10 seconds before moving to next node...
------------------------------------------------------
Performing replication on DC06...
Repadmin can't connect to a "home server", because of the following error. Try specifying a different
home server with /homeserver:[dns name]
Error: An LDAP lookup operation failed with the following error:

LDAP Error 81(0x51): Server Down
Server Win32 Error 0(0x0):
Extended Information:

[CNC-DC02] Connecting to remote server DC06 failed with the following error message : WinRM cannot complete the operation. Verify that the specified
computer name is valid, that the computer is accessible over the network, and that a firewall exception for the WinRM service is enabled and allows
access from this computer. By default, the WinRM firewall exception for public profiles limits access to remote computers within the same local subnet.
For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (DC06:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : WinRMOperationTimeout,PSSessionStateBroken
Waiting 10 seconds before moving to next node...
------------------------------------------------------
Performing replication on DC07...
Repadmin can't connect to a "home server", because of the following error. Try specifying a different
home server with /homeserver:[dns name]
Error: An LDAP lookup operation failed with the following error:

LDAP Error 81(0x51): Server Down
Server Win32 Error 0(0x0):
Extended Information:

[DC07] Connecting to remote server DC07 failed with the following error message : WinRM cannot complete the operation. Verify that the specified
computer name is valid, that the computer is accessible over the network, and that a firewall exception for the WinRM service is enabled and allows
access from this computer. By default, the WinRM firewall exception for public profiles limits access to remote computers within the same local subnet.
For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (DC07:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : WinRMOperationTimeout,PSSessionStateBroken
Waiting 10 seconds before moving to next node...
------------------------------------------------------
Done.

Leave a Reply

Your email address will not be published. Required fields are marked *