546 lines
26 KiB
PowerShell
546 lines
26 KiB
PowerShell
# Abstract: This PoSH Script Checks The SYSVOL Replication Latency/Convergence
|
|
# Written By: Jorge de Almeida Pinto [MVP-DS]
|
|
# Blog: http://jorgequestforknowledge.wordpress.com/
|
|
#
|
|
# 2013-03-02: (v0.1): Initial version of the script
|
|
# 2014-02-01: (v0.2): Updated to also work on W2K3, added STOP option, added few extra columns to output extra info of DCs, better detection of unavailable DCs, and screen adjustment section added
|
|
# 2014-02-09: (v0.3): Solved a bug with regards to the detection/location of RWDCs and RODCs
|
|
# 2014-02-11: (v0.4): Added additional logic to determine if a DC is either an RWDC or RODC when it fails using the first logic and changed the layout a little bit
|
|
#
|
|
# REQUIRES: PowerShell v2.0 or higher
|
|
# REQUIRES: At least 2 RWDCs
|
|
# SUPPORTS: W2K3(R2), W2K8(R2), W2K12(R2) DCs and most likely higher
|
|
# SUPPORTS: NTFRS or DFS-R Replication for the SYSVOL
|
|
#
|
|
# -----> !!! DISCLAIMER/REMARKS !!! <------
|
|
# * The script is freeware, you are free to distribute it, but always refer to this website (http://jorgequestforknowledge.wordpress.com/) as the location where you got it
|
|
# * This script is furnished "AS IS". No warranty is expressed or implied!
|
|
# * Always test first in lab environment to see if it meets your needs!
|
|
# * Use this script at your own risk!
|
|
# * I do not warrant this script to be fit for any purpose, use or environment
|
|
# * I have tried to check everything that needed to be checked, but I do not guarantee the script does not have bugs.
|
|
# * I do not guarantee the script will not damage or destroy your system(s), environment or whatever.
|
|
# * I do not accept any liability in any way if you screw up, use the script wrong or in any other way where damage is caused to your environment/systems!
|
|
# * If you do not accept these terms do not use the script and delete it immediately!
|
|
# -----> !!! DISCLAIMER/REMARKS !!! <------
|
|
|
|
# Clear The Screen
|
|
Clear-Host
|
|
|
|
# Configure The Appropriate Screen And Buffer Size To Make Sure Everything Fits Nicely
|
|
$uiConfig = (Get-Host).UI.RawUI
|
|
$uiConfig.WindowTitle = "+++ CHECKING SYSVOL REPLICATION LATENCY/CONVERGENCE +++"
|
|
$uiConfig.ForegroundColor = "Yellow"
|
|
$uiConfigBufferSize = $uiConfig.BufferSize
|
|
$uiConfigBufferSize.Width = 150
|
|
$uiConfigBufferSize.Height = 9999
|
|
$uiConfigScreenSizeMax = $uiConfig.MaxPhysicalWindowSize
|
|
$uiConfigScreenSizeMaxWidth = $uiConfigScreenSizeMax.Width
|
|
$uiConfigScreenSizeMaxHeight = $uiConfigScreenSizeMax.Height
|
|
$uiConfigScreenSize = $uiConfig.WindowSize
|
|
If ($uiConfigScreenSizeMaxWidth -lt 150) {
|
|
$uiConfigScreenSize.Width = $uiConfigScreenSizeMaxWidth
|
|
} Else {
|
|
$uiConfigScreenSize.Width = 150
|
|
}
|
|
If ($uiConfigScreenSizeMaxHeight -lt 75) {
|
|
$uiConfigScreenSize.Height = $uiConfigScreenSizeMaxHeight - 5
|
|
} Else {
|
|
$uiConfigScreenSize.Height = 75
|
|
}
|
|
$uiConfig.BufferSize = $uiConfigBufferSize
|
|
$uiConfig.WindowSize = $uiConfigScreenSize
|
|
|
|
# Start...
|
|
Write-Host " *******************************************************" -ForeGroundColor Magenta
|
|
Write-Host " * *" -ForeGroundColor Magenta
|
|
Write-Host " * --> Test SYSVOL Replication Latency/Convergence <-- *" -ForeGroundColor Magenta
|
|
Write-Host " * *" -ForeGroundColor Magenta
|
|
Write-Host " * Written By: Jorge de Almeida Pinto [MVP-DS] *" -ForeGroundColor Magenta
|
|
Write-Host " * (http://jorgequestforknowledge.wordpress.com/) *" -ForeGroundColor Magenta
|
|
Write-Host " * *" -ForeGroundColor Magenta
|
|
Write-Host " *******************************************************" -ForeGroundColor Magenta
|
|
|
|
##########
|
|
# Some Constants
|
|
$continue = $true
|
|
$cleanupTempObject = $true
|
|
|
|
##########
|
|
# The Function To Test The Port Connection
|
|
Function PortConnectionCheck($fqdnDC,$port,$timeOut) {
|
|
$tcpPortSocket = $null
|
|
$portConnect = $null
|
|
$tcpPortWait = $null
|
|
$tcpPortSocket = New-Object System.Net.Sockets.TcpClient
|
|
$portConnect = $tcpPortSocket.BeginConnect($fqdnDC,$port,$null,$null)
|
|
$tcpPortWait = $portConnect.AsyncWaitHandle.WaitOne($timeOut,$false)
|
|
If(!$tcpPortWait) {
|
|
$tcpPortSocket.Close()
|
|
#Write-Host "Connection Timeout"
|
|
Return "ERROR"
|
|
} Else {
|
|
#$error.Clear()
|
|
$ErrorActionPreference = "SilentlyContinue"
|
|
$tcpPortSocket.EndConnect($portConnect) | Out-Null
|
|
If (!$?) {
|
|
#Write-Host $error[0]
|
|
Return "ERROR"
|
|
} Else {
|
|
Return "SUCCESS"
|
|
}
|
|
$tcpPortSocket.Close()
|
|
$ErrorActionPreference = "Continue"
|
|
}
|
|
}
|
|
|
|
##########
|
|
# Get The FQDN Of The Local AD Domain From The Server This Script Is Executed On
|
|
$ADDomainToWriteTo = $(Get-WmiObject -Class Win32_ComputerSystem).Domain
|
|
|
|
##########
|
|
# Get List Of Directory Servers In AD Forest
|
|
$ThisADForest = [DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
|
|
$configNCDN = $ThisADForest.schema.Name.Substring(("CN=Schema,").Length)
|
|
$searchRootNTDSdsa = [ADSI]"LDAP://CN=Sites,$configNCDN"
|
|
$searcherNTDSdsaRW = New-Object System.DirectoryServices.DirectorySearcher($searchRootNTDSdsa)
|
|
$searcherNTDSdsaRO = New-Object System.DirectoryServices.DirectorySearcher($searchRootNTDSdsa)
|
|
$searcherNTDSdsaRW.Filter = "(objectCategory=NTDSDSA)"
|
|
$searcherNTDSdsaRO.Filter = "(objectCategory=NTDSDSARO)"
|
|
$objNTDSdsaRW = $searcherNTDSdsaRW.FindAll()
|
|
$objNTDSdsaRO = $searcherNTDSdsaRO.FindAll()
|
|
$TableOfRWDCsInADForest = @()
|
|
$objNTDSdsaRW | %{
|
|
$ntdsDN = $_.Properties.distinguishedname
|
|
$nbtRWDCName = $ntdsDN[0].Substring(("CN=NTDS Settings,CN=").Length)
|
|
$nbtRWDCName = $nbtRWDCName.Substring(0,$nbtRWDCName.IndexOf(","))
|
|
$nbtRWDCSite = $ntdsDN[0].Substring(("CN=NTDS Settings,CN=$nbtRWDCName,CN=Servers,CN=").Length)
|
|
$nbtRWDCSite = $nbtRWDCSite.Substring(0,$nbtRWDCSite.IndexOf(","))
|
|
$TableOfRWDCsInADForestObj = "" | Select "DS Name","Site Name"
|
|
$TableOfRWDCsInADForestObj."DS Name" = $nbtRWDCName
|
|
$TableOfRWDCsInADForestObj."Site Name" = $nbtRWDCSite
|
|
$TableOfRWDCsInADForest += $TableOfRWDCsInADForestObj
|
|
}
|
|
$TableOfRODCsInADForest = @()
|
|
$objNTDSdsaRO | %{
|
|
$ntdsDN = $_.Properties.distinguishedname
|
|
$nbtRODCName = $ntdsDN[0].Substring(("CN=NTDS Settings,CN=").Length)
|
|
$nbtRODCName = $nbtRODCName.Substring(0,$nbtRODCName.IndexOf(","))
|
|
$nbtRODCSite = $ntdsDN[0].Substring(("CN=NTDS Settings,CN=$nbtRODCName,CN=Servers,CN=").Length)
|
|
$nbtRODCSite = $nbtRODCSite.Substring(0,$nbtRODCSite.IndexOf(","))
|
|
$TableOfRODCsInADForestObj = "" | Select "DS Name","Site Name"
|
|
$TableOfRODCsInADForestObj."DS Name" = $nbtRODCName
|
|
$TableOfRODCsInADForestObj."Site Name" = $nbtRODCSite
|
|
$TableOfRODCsInADForest += $TableOfRODCsInADForestObj
|
|
}
|
|
$TableOfDCsInADForest = $TableOfRWDCsInADForest + $TableOfRODCsInADForest
|
|
|
|
##########
|
|
# Get List Of DCs In AD Domain, Create And Present In A Table
|
|
$contextADDomainToWriteTo = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$ADDomainToWriteTo)
|
|
$ListOfDCsInADDomain = [System.DirectoryServices.ActiveDirectory.DomainController]::findall($contextADDomainToWriteTo)
|
|
$ListOfRWDCsInADDomain = $ListOfDCsInADDomain | ?{$_.InboundConnections -ne $null -and !($_.InboundConnections -match "RODC Connection")}
|
|
$ListOfRODCsInADDomain = $ListOfDCsInADDomain | ?{$_.InboundConnections -match "RODC Connection"}
|
|
$TableOfDCsInADDomain = @()
|
|
Write-Host ""
|
|
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
|
|
Write-Host "LIST OF DCs IN THE AD DOMAIN '$ADDomainToWriteTo'..." -ForeGroundColor Cyan
|
|
ForEach ($DC in $ListOfDCsInADDomain) {
|
|
$TableOfDCsInADDomainObj = "" | Select Name,PDC,"Site Name","DS Type","IP Address","OS Version"
|
|
$TableOfDCsInADDomainObj.Name = $DC.Name
|
|
$TableOfDCsInADDomainObj.PDC = "FALSE"
|
|
If ($DC.Roles -ne $null -And $DC.Roles -Contains "PdcRole") {
|
|
$TableOfDCsInADDomainObj.PDC = "TRUE"
|
|
$pdcFQDN = $DC.Name
|
|
$pdcSite = $DC.SiteName
|
|
}
|
|
If ( $DC.SiteName -ne $null -And $DC.SiteName -ne "") {
|
|
$TableOfDCsInADDomainObj."Site Name" = $DC.SiteName
|
|
} Else {
|
|
If (($TableOfDCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))} | Measure-Object).Count -eq 1) {
|
|
$TableOfDCsInADDomainObj."Site Name" = ($TableOfDCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))})."Site Name"
|
|
}
|
|
If (($TableOfDCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))} | Measure-Object).Count -eq 0) {
|
|
$TableOfDCsInADDomainObj."Site Name" = "<Fail>"
|
|
}
|
|
If (($TableOfDCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))} | Measure-Object).Count -gt 1) {
|
|
$TableOfDCsInADDomainObj."Site Name" = "<Fail>"
|
|
}
|
|
}
|
|
$DStype = $null
|
|
If ($DStype -eq $null) {
|
|
ForEach ($RWDC In $ListOfRWDCsInADDomain) {
|
|
If ($RWDC.Name -like $DC.Name) {
|
|
$DStype = "Read/Write"
|
|
BREAK
|
|
}
|
|
}
|
|
}
|
|
If ($DStype -eq $null) {
|
|
ForEach ($RODC In $ListOfRODCsInADDomain) {
|
|
If ($RODC.Name -like $DC.Name) {
|
|
$DStype = "Read-Only"
|
|
BREAK
|
|
}
|
|
}
|
|
}
|
|
If ($DStype -eq $null) {
|
|
$DStype = "<Unknown>"
|
|
|
|
If (($TableOfRWDCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))} | Measure-Object).Count -eq 1) {
|
|
$DStype = "Read/Write"
|
|
}
|
|
If (($TableOfRODCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))} | Measure-Object).Count -eq 1) {
|
|
$DStype = "Read-Only"
|
|
}
|
|
}
|
|
$TableOfDCsInADDomainObj."DS Type" = $DStype
|
|
If ($DC.IPAddress -ne $null -And $DC.IPAddress -ne "") {
|
|
$TableOfDCsInADDomainObj."IP Address" = $DC.IPAddress
|
|
} Else {
|
|
$TableOfDCsInADDomainObj."IP Address" = "<Fail>"
|
|
}
|
|
If ($DC.OSVersion -ne $null -And $DC.OSVersion -ne "") {
|
|
$TableOfDCsInADDomainObj."OS Version" = $DC.OSVersion
|
|
} Else {
|
|
$TableOfDCsInADDomainObj."OS Version" = "<Fail>"
|
|
}
|
|
$TableOfDCsInADDomain += $TableOfDCsInADDomainObj
|
|
}
|
|
$TableOfDCsInADDomain | FT -AutoSize
|
|
Write-Host " --> Found [$($ListOfDCsInADDomain.count)] DC(s) In AD Domain..." -ForeGroundColor Cyan
|
|
Write-Host ""
|
|
|
|
##########
|
|
# Specify A RWDC From The Selected AD Domain
|
|
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
|
|
Write-Host "Which RWDC In The AD Domain '$ADDomainToWriteTo' Should Be Used To Create The Object?" -ForeGroundColor Cyan
|
|
Write-Host ""
|
|
Write-Host "Available Options Are:" -ForeGroundColor Yellow
|
|
Write-Host "[*] Specify 'PDC' To Use The DC With The PDC FSMO Role" -ForeGroundColor Yellow
|
|
Write-Host "[*] Just Press Enter To Locate An RWDC" -ForeGroundColor Yellow
|
|
Write-Host "[*] Specify The FQDN Of A Specific RWDC" -ForeGroundColor Yellow
|
|
Write-Host "[*] Specify 'STOP' To End The Script" -ForeGroundColor Yellow
|
|
Write-Host ""
|
|
$SourceRWDCInADDomain = Read-Host "Please Choose An Option"
|
|
|
|
# If PDC Was Specified Find The RWDC With The PDC FSMO Role And Use That
|
|
If ($SourceRWDCInADDomain -eq "PDC") {
|
|
$SourceRWDCInADDomainFQDN = $pdcFQDN
|
|
$SourceRWDCInADDomainSITE = $pdcSite
|
|
}
|
|
|
|
# If Nothing Was Specified Automatically Locate An RWDC To Use
|
|
If ($SourceRWDCInADDomain -eq "") {
|
|
# Locate Just ONE DC (This Could Be An RWDC Or RODC)
|
|
$SourceRWDCInADDomainObjectONE = [System.DirectoryServices.ActiveDirectory.DomainController]::findone($contextADDomainToWriteTo)
|
|
|
|
# Locate All RWDCs In The AD Domain
|
|
$SourceRWDCInADDomainObjectALL = $ListOfRWDCsInADDomain
|
|
$UseRWDC = $False
|
|
|
|
# Check If The Single DC Found Is An RWDC Or Not By Checking If It Is In The List Of RWDCs
|
|
ForEach ($RWDC In $SourceRWDCInADDomainObjectALL) {
|
|
If ($RWDC.Name -like $SourceRWDCInADDomainObjectONE.Name) {
|
|
$UseRWDC = $True
|
|
}
|
|
}
|
|
|
|
# If The Single DC Found Is An RWDC, Then Use That One
|
|
If ($UseRWDC -eq $True) {
|
|
$SourceRWDCInADDomainFQDN = $SourceRWDCInADDomainObjectONE.Name
|
|
$SourceRWDCInADDomainSITE = $SourceRWDCInADDomainObjectONE.SiteName
|
|
}
|
|
|
|
# If The Single DC Found Is An RODC, Then Find The RWDC With The PDC FSMO Role And Use That
|
|
If ($UseRWDC -eq $False) {
|
|
$SourceRWDCInADDomainFQDN = $pdcFQDN
|
|
$SourceRWDCInADDomainSITE = $pdcSite
|
|
}
|
|
|
|
}
|
|
|
|
# If A Specific RWDC Was Specified Then Use That One
|
|
If ($SourceRWDCInADDomain -ne "" -And $SourceRWDCInADDomain -ne "PDC" -And $SourceRWDCInADDomain -ne "STOP") {
|
|
$contextRWDCToWriteTo = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$SourceRWDCInADDomain)
|
|
$SourceRWDCInADDomainObject = [System.DirectoryServices.ActiveDirectory.DomainController]::GetDomainController($contextRWDCToWriteTo)
|
|
$SourceRWDCInADDomainFQDN = $SourceRWDCInADDomainObject.Name
|
|
$SourceRWDCInADDomainSITE = $SourceRWDCInADDomainObject.SiteName
|
|
}
|
|
|
|
# If STOP Was Specified Then End The Script
|
|
If ($SourceRWDCInADDomain -eq "STOP") {
|
|
Write-Host ""
|
|
Write-Host "'STOP' Was Specified..." -ForeGroundColor Red
|
|
Write-Host "Aborting Script..." -ForeGroundColor Red
|
|
Write-Host ""
|
|
EXIT
|
|
}
|
|
|
|
# Check If The Selected DC Actually Exists In The AD Domain And Its Is An RWDC And NOT An RODC
|
|
$RWDCvalidity = $False
|
|
ForEach ($DC in $ListOfRWDCsInADDomain) {
|
|
If ($DC.Name -like $SourceRWDCInADDomainFQDN) {
|
|
$RWDCvalidity = $True
|
|
}
|
|
}
|
|
Write-Host ""
|
|
Write-Host "Checking Existence And Connectivity Of The Specified RWDC '$SourceRWDCInADDomainFQDN' In The AD Domain '$ADDomainToWriteTo'..." -ForeGroundColor Yellow
|
|
If ($RWDCvalidity -eq $True) {
|
|
Write-Host ""
|
|
Write-Host "The Specified DC '$SourceRWDCInADDomainFQDN' Is An RWDC And It Exists In The AD Domain '$ADDomainToWriteTo'!" -ForeGroundColor Green
|
|
Write-Host ""
|
|
Write-Host "Continuing Script..." -ForeGroundColor Green
|
|
$smbPort = "445"
|
|
$timeOut = "500"
|
|
$smbConnectionResult = $null
|
|
$fqdnDC = $SourceRWDCInADDomainFQDN
|
|
$smbConnectionResult = PortConnectionCheck $fqdnDC $smbPort $timeOut
|
|
If ($smbConnectionResult -eq "SUCCESS") {
|
|
Write-Host ""
|
|
Write-Host "The Specified RWDC '$SourceRWDCInADDomainFQDN' Is Reachable!" -ForeGroundColor Green
|
|
Write-Host ""
|
|
Write-Host "Continuing Script..." -ForeGroundColor Green
|
|
Write-Host ""
|
|
}
|
|
If ($smbConnectionResult -eq "ERROR") {
|
|
Write-Host ""
|
|
Write-Host "The Specified RWDC '$SourceRWDCInADDomainFQDN' Is NOT Reachable!" -ForeGroundColor Red
|
|
Write-Host ""
|
|
Write-Host "Please Re-Run The Script And Make Sure To Use An RWDC That Is Reachable!" -ForeGroundColor Red
|
|
Write-Host ""
|
|
Write-Host "Aborting Script..." -ForeGroundColor Red
|
|
Write-Host ""
|
|
Break
|
|
}
|
|
}
|
|
If ($RWDCvalidity -eq $False) {
|
|
Write-Host ""
|
|
Write-Host "The Specified DC '$SourceRWDCInADDomainFQDN' Either Does NOT Exist In The AD Domain '$ADDomainToWriteTo' Or Is NOT And RWDC!" -ForeGroundColor Red
|
|
Write-Host ""
|
|
Write-Host "Please Re-Run The Script And Provide The FQDN Of An RWDC Within The AD Domain '$ADDomainToWriteTo' That Does Exist" -ForeGroundColor Red
|
|
Write-Host ""
|
|
Write-Host "Aborting Script..." -ForeGroundColor Red
|
|
Write-Host ""
|
|
Break
|
|
}
|
|
|
|
##########
|
|
# Determine SYSVOL Replication Mechanism And SYSVOL/NetLogon Location On Sourcing RWDC
|
|
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
|
|
Write-Host "SYSVOL REPLICATION MECHANISM..." -ForeGroundColor Cyan
|
|
Write-Host ""
|
|
|
|
# Get The Default Naming Contexr
|
|
$defaultNamingContext = (([ADSI]"LDAP://$SourceRWDCInADDomainFQDN/rootDSE").defaultNamingContext)
|
|
|
|
# Find The Computer Account Of The Sourcing RWDC
|
|
$Searcher = New-Object DirectoryServices.DirectorySearcher
|
|
$Searcher.Filter = "(&(objectClass=computer)(dNSHostName=$SourceRWDCInADDomainFQDN))"
|
|
$Searcher.SearchRoot = "LDAP://" + $SourceRWDCInADDomainFQDN + "/OU=Domain Controllers," + $defaultNamingContext
|
|
# The following appears NOT to work on W2K3, but it does upper-level OSes
|
|
# $dcObjectPath = $Searcher.FindAll().Path
|
|
# The following appears to work on all OSes
|
|
$dcObjectPath = $Searcher.FindAll() | %{$_.Path}
|
|
|
|
# Check If An NTFRS Subscriber Object Exists To Determine If NTFRS Is Being Used Instead Of DFS-R
|
|
$SearcherNTFRS = New-Object DirectoryServices.DirectorySearcher
|
|
$SearcherNTFRS.Filter = "(&(objectClass=nTFRSSubscriber)(name=Domain System Volume (SYSVOL share)))"
|
|
$SearcherNTFRS.SearchRoot = $dcObjectPath
|
|
$ntfrsSubscriptionObject = $SearcherNTFRS.FindAll()
|
|
If ($ntfrsSubscriptionObject -ne $null) {
|
|
Write-Host "SYSVOL Replication Mechanism Being Used...: NTFRS"
|
|
# Get The Local Root Path For The SYSVOL
|
|
# The following appears NOT to work on W2K3, but it does upper-level OSes
|
|
# $sysvolRootPathOnSourcingRWDC = $ntfrsSubscriptionObject.Properties.frsrootpath
|
|
# The following appears to work on all OSes
|
|
$sysvolRootPathOnSourcingRWDC = $ntfrsSubscriptionObject | %{$_.Properties.frsrootpath}
|
|
}
|
|
|
|
# Check If An DFS-R Subscriber Object Exists To Determine If DFS-R Is Being Used Instead Of NTFRS
|
|
$SearcherDFSR = New-Object DirectoryServices.DirectorySearcher
|
|
$SearcherDFSR.Filter = "(&(objectClass=msDFSR-Subscription)(name=SYSVOL Subscription))"
|
|
$SearcherDFSR.SearchRoot = $dcObjectPath
|
|
$dfsrSubscriptionObject = $SearcherDFSR.FindAll()
|
|
If ($dfsrSubscriptionObject -ne $null) {
|
|
Write-Host "SYSVOL Replication Mechanism Being Used...: DFS-R" -ForeGroundColor Yellow
|
|
Write-Host ""
|
|
# Get The Local Root Path For The SYSVOL
|
|
# The following appears NOT to work on W2K3, but it does not upper-level OSes. NOT really needed, because W2K3 does not support DFS-R for SYSVOL!
|
|
# $sysvolRootPathOnSourcingRWDC = $dfsrSubscriptionObject.Properties."msdfsr-rootpath"
|
|
# The following appears to work on all OSes
|
|
$sysvolRootPathOnSourcingRWDC = $dfsrSubscriptionObject | %{$_.Properties."msdfsr-rootpath"}
|
|
}
|
|
|
|
# Determine The UNC Of The Folder To Write The Temp File To
|
|
$scriptsUNCPathOnSourcingRWDC = "\\" + $SourceRWDCInADDomainFQDN + "\" + $($sysvolRootPathOnSourcingRWDC.Replace(":","$")) + "\Scripts"
|
|
##########
|
|
# Get List Of DCs In AD Domain To Which The Temp Object Will Replicate, Create And Present In A Table
|
|
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
|
|
Write-Host "LIST OF DIRECTORY SERVERS THE TEMP OBJECT REPLICATES TO..." -ForeGroundColor Cyan
|
|
|
|
# Put The Selected RWDC Already In the Table [A] Of Directory Servers To Which The Temp Object Will Replicate
|
|
$TableOfDSServersA = @()
|
|
$TableOfDSServersAObj = "" | Select Name,"Site Name",Reachable
|
|
$TableOfDSServersAObj.Name = ("$SourceRWDCInADDomainFQDN [SOURCE RWDC]").ToUpper()
|
|
$TableOfDSServersAObj."Site Name" = $SourceRWDCInADDomainSITE
|
|
$TableOfDSServersAObj.Reachable = "TRUE"
|
|
$TableOfDSServersA += $TableOfDSServersAObj
|
|
|
|
# Put The Selected RWDC Already In the Table [B] Of Directory Servers Where The Replication Starts
|
|
$TableOfDSServersB = @()
|
|
$TableOfDSServersBObj = "" | Select Name,"Site Name",Time
|
|
$TableOfDSServersBObj.Name = ("$SourceRWDCInADDomainFQDN [SOURCE RWDC]").ToUpper()
|
|
$TableOfDSServersBObj."Site Name" = $SourceRWDCInADDomainSITE
|
|
$TableOfDSServersBObj.Time = 0.00
|
|
$TableOfDSServersB += $TableOfDSServersBObj
|
|
|
|
# Add All Other Remaining DCs In The Targeted AD Domain To The List Of Directory Servers [A]
|
|
ForEach ($DC In $ListOfDCsInADDomain) {
|
|
If(!($DC.Name -like $SourceRWDCInADDomainFQDN)) {
|
|
$TableOfDSServersAObj = "" | Select Name,"Site Name",Reachable
|
|
$TableOfDSServersAObj.Name = $DC.Name
|
|
If ($DC.SiteName -ne $null -And $DC.SiteName -ne "") {
|
|
$TableOfDSServersAObj."Site Name" = $DC.SiteName
|
|
} Else {
|
|
If (($TableOfDCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))} | Measure-Object).Count -eq 1) {
|
|
$TableOfDSServersAObj."Site Name" = ($TableOfDCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))})."Site Name"
|
|
}
|
|
If (($TableOfDCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))} | Measure-Object).Count -eq 0) {
|
|
$TableOfDSServersAObj."Site Name" = "<Fail>"
|
|
}
|
|
If (($TableOfDCsInADForest | ?{$_."DS Name" -eq $($($DC.Name).Substring(0,$($DC.Name).IndexOf(".")))} | Measure-Object).Count -gt 1) {
|
|
$TableOfDSServersAObj."Site Name" = "<Fail>"
|
|
}
|
|
}
|
|
$smbPort = "445"
|
|
$timeOut = "500"
|
|
$smbConnectionResult = $null
|
|
$fqdnDC = $DC.Name
|
|
$smbConnectionResult = PortConnectionCheck $fqdnDC $smbPort $timeOut
|
|
If ($smbConnectionResult -eq "SUCCESS") {
|
|
$TableOfDSServersAObj.Reachable = "TRUE"
|
|
}
|
|
If ($smbConnectionResult -eq "ERROR") {
|
|
$TableOfDSServersAObj.Reachable = "FALSE"
|
|
}
|
|
$TableOfDSServersA += $TableOfDSServersAObj
|
|
}
|
|
}
|
|
$TableOfDSServersA | FT -AutoSize
|
|
Write-Host " --> Found [$($TableOfDSServersA.count)] Directory Server(s)..." -ForeGroundColor Cyan
|
|
Write-Host ""
|
|
|
|
##########
|
|
# Create The Temp Object On The Targeted RWDC
|
|
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------" -ForeGroundColor Cyan
|
|
Write-Host "CREATING TEMP TEXT FILE IN SYSVOL/NETLOGON...:" -ForeGroundColor Cyan
|
|
Write-Host ""
|
|
$domainNCDN = $defaultNamingContext
|
|
$tempObjectName = "sysvolReplTempObject" + (Get-Date -f yyyyMMddHHmmss) + ".txt"
|
|
Write-Host " --> On RWDC.............: $SourceRWDCInADDomainFQDN" -ForeGroundColor Yellow
|
|
Write-Host " --> With Full Name......: $tempObjectName" -ForeGroundColor Yellow
|
|
Write-Host " --> With Contents.......: ...!!!...TEMP OBJECT TO TEST SYSVOL REPLICATION LATENCY/CONVERGENCE...!!!..." -ForeGroundColor Yellow
|
|
Write-Host " --> In AD Domain........: $ADDomainToWriteTo ($domainNCDN)" -ForeGroundColor Yellow
|
|
"...!!!...TEMP OBJECT TO TEST AD REPLICATION LATENCY/CONVERGENCE...!!!..." | Out-File -FilePath $($scriptsUNCPathOnSourcingRWDC + "\" + $tempObjectName)
|
|
Write-Host "`n Temp Text File [$tempObjectName] Has Been Created In The NetLogon Share Of RWDC [$SourceRWDCInADDomainFQDN]! `n" -ForeGroundColor Yellow
|
|
|
|
##########
|
|
# Go Through The Process Of Checking Each Directory Server To See If The Temp Object Already Has Replicated To It
|
|
$startDateTime = Get-Date
|
|
$i = 0
|
|
Write-Host " --> Found [$($TableOfDSServersA.count)] Directory Server(s)..." -ForeGroundColor Yellow
|
|
Write-Host ""
|
|
While($continue) {
|
|
$i++
|
|
$oldpos = $host.UI.RawUI.CursorPosition
|
|
Write-Host " ====================== CHECK $i ======================" -ForeGroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host " REMARK: Each DC In The List Below Must Be At Least Accessible Through SMB Over TCP (445)" -ForeGroundColor Red
|
|
Write-Host ""
|
|
Start-Sleep 1
|
|
$replicated = $true
|
|
|
|
# For Each Directory Server In The List/Table [A] Perform A Number Of Steps
|
|
ForEach ($DSsrv in $TableOfDSServersA) {
|
|
If ($DSsrv.Name -match $SourceRWDCInADDomainFQDN) {
|
|
Write-Host " * Contacting DC In AD domain ...[$($DSsrv.Name.ToUpper())]..." -ForeGroundColor Yellow
|
|
Write-Host " - DC Is Reachable..." -ForeGroundColor Green
|
|
Write-Host " - Object [$tempObjectName] Exists In The NetLogon Share" (" "*3) -ForeGroundColor Green
|
|
continue
|
|
}
|
|
|
|
# If The Directory Server Is A DC In The AD Domain, Then Connect Through LDAP (TCP:445)
|
|
If ($DSsrv.Name -notmatch $SourceRWDCInADDomainFQDN) {
|
|
Write-Host ""
|
|
Write-Host " * Contacting DC In AD domain ...[$($DSsrv.Name.ToUpper())]..." -ForeGroundColor Yellow
|
|
$connectionResult = $null
|
|
If ($DSsrv.Reachable -eq "TRUE") {
|
|
Write-Host " - DC Is Reachable..." -ForeGroundColor Green
|
|
$objectPath = "\\" + $($DSsrv.Name) + "\Netlogon\" + $tempObjectName
|
|
$connectionResult = "SUCCESS"
|
|
}
|
|
If ($DSsrv.Reachable -eq "FALSE") {
|
|
Write-Host " - DC Is NOT Reachable..." -ForeGroundColor Red
|
|
$connectionResult = "FAILURE"
|
|
}
|
|
}
|
|
|
|
# If The Connection To The DC Is Successful
|
|
If ($connectionResult -eq "SUCCESS") {
|
|
If (Test-Path -Path $objectPath) {
|
|
# If The Temp Object Already Exists
|
|
Write-Host " - Object [$tempObjectName] Now Does Exist In The NetLogon Share" (" "*3) -ForeGroundColor Green
|
|
If (!($TableOfDSServersB | ?{$_.Name -match $DSsrv.Name})) {
|
|
$TableOfDSServersBobj = "" | Select Name,"Site Name",Time
|
|
$TableOfDSServersBobj.Name = $DSsrv.Name
|
|
$TableOfDSServersBObj."Site Name" = $DSsrv."Site Name"
|
|
$TableOfDSServersBObj.Time = ("{0:n2}" -f ((Get-Date)-$startDateTime).TotalSeconds)
|
|
$TableOfDSServersB += $TableOfDSServersBObj
|
|
}
|
|
} Else {
|
|
# If The Temp Object Does Not Yet Exist
|
|
Write-Host " - Object [$tempObjectName] Does NOT Exist Yet In The NetLogon Share" -ForeGroundColor Red
|
|
$replicated = $false
|
|
}
|
|
}
|
|
|
|
# If The Connection To The DC Is Unsuccessful
|
|
If ($connectionResult -eq "FAILURE") {
|
|
Write-Host " - Unable To Connect To DC/GC And Check For The Temp Object..." -ForeGroundColor Red
|
|
If (!($TableOfDSServersB | ?{$_.Name -match $DSsrv.Name})) {
|
|
$TableOfDSServersBobj = "" | Select Name,"Site Name",Time
|
|
$TableOfDSServersBobj.Name = $DSsrv.Name
|
|
$TableOfDSServersBObj."Site Name" = $DSsrv."Site Name"
|
|
$TableOfDSServersBObj.Time = "<Fail>"
|
|
$TableOfDSServersB += $TableOfDSServersBObj
|
|
}
|
|
}
|
|
}
|
|
If ($replicated) {
|
|
$continue = $false
|
|
} Else {
|
|
$host.UI.RawUI.CursorPosition = $oldpos
|
|
}
|
|
}
|
|
|
|
##########
|
|
# Show The Start Time, The End Time And The Duration Of The Replication
|
|
$endDateTime = Get-Date
|
|
$duration = "{0:n2}" -f ($endDateTime.Subtract($startDateTime).TotalSeconds)
|
|
Write-Host "`n Start Time......: $(Get-Date $startDateTime -format "yyyy-MM-dd HH:mm:ss")" -ForeGroundColor Yellow
|
|
Write-Host " End Time........: $(Get-Date $endDateTime -format "yyyy-MM-dd HH:mm:ss")" -ForeGroundColor Yellow
|
|
Write-Host " Duration........: $duration Seconds" -ForeGroundColor Yellow
|
|
|
|
##########
|
|
# Delete The Temp Object On The RWDC
|
|
If ($cleanupTempObject) {
|
|
Write-Host ""
|
|
Write-Host " Deleting Temp Text File... `n" -ForeGroundColor Yellow
|
|
Remove-Item $($scriptsUNCPathOnSourcingRWDC + "\" + $tempObjectName) -Force
|
|
Write-Host " Temp Text File [$tempObjectName] Has Been Deleted On The Target RWDC! `n" -ForeGroundColor Yellow
|
|
}
|
|
|
|
##########
|
|
# Output The Table [B] Containing The Information Of Each Directory Server And How Long It Took To Reach That Directory Server After The Creation On The Source RWDC
|
|
$TableOfDSServersB | Sort-Object Time | FT -AutoSize |