Use scheduled task replication via source DC session
This commit is contained in:
91
certy.ps1
91
certy.ps1
@@ -266,6 +266,7 @@ function Invoke-Replication {
|
|||||||
[string]$Command,
|
[string]$Command,
|
||||||
[bool]$UseRemote,
|
[bool]$UseRemote,
|
||||||
[pscredential]$Credential,
|
[pscredential]$Credential,
|
||||||
|
[string]$SourceDc,
|
||||||
[scriptblock]$Log
|
[scriptblock]$Log
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -276,47 +277,61 @@ function Invoke-Replication {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
$sessions = @{}
|
if ([string]::IsNullOrWhiteSpace($SourceDc)) {
|
||||||
|
& $Log "Replication skipped: source DC is empty."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$session = $null
|
||||||
try {
|
try {
|
||||||
|
if ($UseRemote) {
|
||||||
|
try {
|
||||||
|
if ($Credential) {
|
||||||
|
$session = New-PSSession -ComputerName $SourceDc -Credential $Credential -ErrorAction Stop
|
||||||
|
} else {
|
||||||
|
$session = New-PSSession -ComputerName $SourceDc -ErrorAction Stop
|
||||||
|
}
|
||||||
|
& $Log "Replication session opened: $SourceDc"
|
||||||
|
} catch {
|
||||||
|
& $Log ("Replication session error on {0}: {1}" -f $SourceDc, $_.Exception.Message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($server in $targets) {
|
foreach ($server in $targets) {
|
||||||
$usesToken = $Command -match "\{server\}"
|
$usesToken = $Command -match "\{server\}|\{dest\}"
|
||||||
$cmd = if ($usesToken) { $Command.Replace("{server}", $server) } else { $Command }
|
$cmd = $Command.Replace("{server}", $server).Replace("{dest}", $server)
|
||||||
$cmd = $cmd.Trim()
|
$cmd = $cmd.Trim()
|
||||||
if ($cmd -match "^(?i)\s*/repadmin\b") {
|
if ($cmd -match "^(?i)\s*/repadmin\b") {
|
||||||
$cmd = $cmd -replace "^(?i)\s*/repadmin\b", "repadmin"
|
$cmd = $cmd -replace "^(?i)\s*/repadmin\b", "repadmin"
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($UseRemote) {
|
if ($UseRemote) {
|
||||||
if (-not $sessions.ContainsKey($server)) {
|
$taskName = ("OneShot_AD_DNS_Repl_{0}" -f ($server -replace "[^A-Za-z0-9_-]", "_"))
|
||||||
try {
|
$outFile = ("C:\Windows\Temp\repadmin-{0}.txt" -f $server)
|
||||||
if ($Credential) {
|
$repadminCmd = $cmd
|
||||||
$sessions[$server] = New-PSSession -ComputerName $server -Credential $Credential -ErrorAction Stop
|
$repadminCmd = [regex]::Replace($repadminCmd, "\s{2,}", " ").Trim()
|
||||||
} else {
|
if ([string]::IsNullOrWhiteSpace($repadminCmd)) {
|
||||||
$sessions[$server] = New-PSSession -ComputerName $server -ErrorAction Stop
|
|
||||||
}
|
|
||||||
& $Log "Replication session opened: $server"
|
|
||||||
} catch {
|
|
||||||
& $Log ("Replication session error on {0}: {1}" -f $server, $_.Exception.Message)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$remoteCmd = $cmd.Replace("{server}", "").Trim()
|
|
||||||
$remoteCmd = [regex]::Replace($remoteCmd, "\s{2,}", " ")
|
|
||||||
if ($remoteCmd -match "(?i)\brepadmin\b" -and $remoteCmd -match "(?i)\bsyncall\b") {
|
|
||||||
$remoteCmd = [regex]::Replace($remoteCmd, "(?i)\brepadmin\s+/syncall\s+\S+", "repadmin /syncall")
|
|
||||||
}
|
|
||||||
$remoteCmd = [regex]::Replace($remoteCmd, "(?i)\brepadmin\s+/syncall\b", "repadmin /syncall")
|
|
||||||
$remoteCmd = $remoteCmd.Replace("/AdeP", "/AedP")
|
|
||||||
$remoteCmd = [regex]::Replace($remoteCmd, "\s{2,}", " ").Trim()
|
|
||||||
if ([string]::IsNullOrWhiteSpace($remoteCmd)) {
|
|
||||||
& $Log "Replication skipped: empty command for $server."
|
& $Log "Replication skipped: empty command for $server."
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
& $Log "Replication (remote): $server -> $remoteCmd"
|
|
||||||
|
& $Log "Replication (scheduled task): $SourceDc -> $server"
|
||||||
try {
|
try {
|
||||||
Invoke-Command -Session $sessions[$server] -ScriptBlock { param($c) & $env:ComSpec /c $c } -ArgumentList $remoteCmd |
|
Invoke-Command -Session $session -ScriptBlock {
|
||||||
ForEach-Object { & $Log $_ }
|
param($DestDC, $TaskName, $OutFile, $RepadminCmd)
|
||||||
|
|
||||||
|
$cmdLine = "cmd.exe /c $RepadminCmd > `"$OutFile`" 2>&1"
|
||||||
|
schtasks /Create /F /TN $TaskName /RU SYSTEM /SC ONCE /ST 00:00 /TR $cmdLine | Out-Null
|
||||||
|
schtasks /Run /TN $TaskName | Out-Null
|
||||||
|
Start-Sleep 6
|
||||||
|
|
||||||
|
$output = if (Test-Path $OutFile) { Get-Content $OutFile } else { "No output file found" }
|
||||||
|
schtasks /Delete /F /TN $TaskName | Out-Null
|
||||||
|
Remove-Item $OutFile -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
$output
|
||||||
|
} -ArgumentList $server, $taskName, $outFile, $repadminCmd | ForEach-Object { & $Log $_ }
|
||||||
} catch {
|
} catch {
|
||||||
& $Log ("Replication error on {0}: {1}" -f $server, $_.Exception.Message)
|
& $Log ("Replication error on {0}: {1}" -f $server, $_.Exception.Message)
|
||||||
}
|
}
|
||||||
@@ -333,7 +348,7 @@ function Invoke-Replication {
|
|||||||
& $env:ComSpec /c $cmd | ForEach-Object { & $Log $_ }
|
& $env:ComSpec /c $cmd | ForEach-Object { & $Log $_ }
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
foreach ($session in $sessions.Values) {
|
if ($session) {
|
||||||
try { Remove-PSSession -Session $session } catch {}
|
try { Remove-PSSession -Session $session } catch {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -626,7 +641,7 @@ $panel.Controls.Add($ipRefreshBtn)
|
|||||||
Style-ButtonSecondary $ipRefreshBtn
|
Style-ButtonSecondary $ipRefreshBtn
|
||||||
$y += $rowHeight + $gap
|
$y += $rowHeight + $gap
|
||||||
|
|
||||||
Add-Label "Primary DNS server" $xLabel $y $labelWidth $rowHeight
|
Add-Label "Primary DNS server (source DC)" $xLabel $y $labelWidth $rowHeight
|
||||||
$dnsServerBox = New-Object System.Windows.Forms.ComboBox
|
$dnsServerBox = New-Object System.Windows.Forms.ComboBox
|
||||||
$dnsServerBox.Location = [System.Drawing.Point]::new($xInput, $y)
|
$dnsServerBox.Location = [System.Drawing.Point]::new($xInput, $y)
|
||||||
$dnsServerBox.Size = [System.Drawing.Size]::new(($inputWidth - ($buttonWidth + $buttonGap)), $rowHeight)
|
$dnsServerBox.Size = [System.Drawing.Size]::new(($inputWidth - ($buttonWidth + $buttonGap)), $rowHeight)
|
||||||
@@ -671,9 +686,9 @@ $panel.Controls.Add($primaryFromSelectedBtn)
|
|||||||
Style-ButtonSecondary $primaryFromSelectedBtn
|
Style-ButtonSecondary $primaryFromSelectedBtn
|
||||||
$y += 70 + $gap
|
$y += 70 + $gap
|
||||||
|
|
||||||
Add-Label "Replication command ({server} optional)" $xLabel $y $labelWidth $rowHeight
|
Add-Label "Replication command ({dest} optional)" $xLabel $y $labelWidth $rowHeight
|
||||||
$replicationCmdBox = Add-TextBox $xInput $y $inputWidth $rowHeight $false
|
$replicationCmdBox = Add-TextBox $xInput $y $inputWidth $rowHeight $false
|
||||||
$replicationCmdBox.Text = "repadmin /syncall /AedP"
|
$replicationCmdBox.Text = "repadmin /syncall {dest} /AdeP"
|
||||||
$y += $rowHeight + $gap
|
$y += $rowHeight + $gap
|
||||||
|
|
||||||
Add-Label "Replication wait (seconds)" $xLabel $y $labelWidth $rowHeight
|
Add-Label "Replication wait (seconds)" $xLabel $y $labelWidth $rowHeight
|
||||||
@@ -681,7 +696,7 @@ $replicationDelayBox = Add-TextBox $xInput $y $inputWidth $rowHeight $false
|
|||||||
$replicationDelayBox.Text = "30"
|
$replicationDelayBox.Text = "30"
|
||||||
$y += $rowHeight + $gap
|
$y += $rowHeight + $gap
|
||||||
|
|
||||||
$replicationRemoteBox = Add-CheckBox "Run repadmin remotely (PowerShell)" $xInput $y $inputWidth $rowHeight
|
$replicationRemoteBox = Add-CheckBox "Run replication via scheduled task on source DC" $xInput $y $inputWidth $rowHeight
|
||||||
$replicationRemoteBox.Checked = $true
|
$replicationRemoteBox.Checked = $true
|
||||||
$y += $rowHeight + $gap
|
$y += $rowHeight + $gap
|
||||||
|
|
||||||
@@ -1197,7 +1212,13 @@ $runBtn.Add_Click({
|
|||||||
& $logAction "Replication credentials saved for this user."
|
& $logAction "Replication credentials saved for this user."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Invoke-Replication -Servers $replicationTargets -Command $replicationCmdBox.Text -UseRemote $replicationRemoteBox.Checked -Credential $replicationCredential -Log $logAction
|
Invoke-Replication `
|
||||||
|
-Servers $replicationTargets `
|
||||||
|
-Command $replicationCmdBox.Text `
|
||||||
|
-UseRemote $replicationRemoteBox.Checked `
|
||||||
|
-Credential $replicationCredential `
|
||||||
|
-SourceDc $dnsServer `
|
||||||
|
-Log $logAction
|
||||||
if ($replicationDelaySeconds -gt 0) {
|
if ($replicationDelaySeconds -gt 0) {
|
||||||
& $logAction "Waiting $replicationDelaySeconds seconds for replication."
|
& $logAction "Waiting $replicationDelaySeconds seconds for replication."
|
||||||
Start-Sleep -Seconds $replicationDelaySeconds
|
Start-Sleep -Seconds $replicationDelaySeconds
|
||||||
|
|||||||
Reference in New Issue
Block a user