diff --git a/certy.ps1 b/certy.ps1 index 6beae28..cd0805f 100644 --- a/certy.ps1 +++ b/certy.ps1 @@ -237,6 +237,7 @@ function Invoke-Replication { param( [string[]]$Servers, [string]$Command, + [bool]$UseRemote, [scriptblock]$Log ) @@ -248,13 +249,27 @@ function Invoke-Replication { } foreach ($server in $targets) { - $cmd = if ($Command -match "\{server\}") { $Command.Replace("{server}", $server) } else { $Command } + $usesToken = $Command -match "\{server\}" + $cmd = if ($usesToken) { $Command.Replace("{server}", $server) } else { $Command } $cmd = $cmd.Trim() if ($cmd -match "^(?i)\s*/repadmin\b") { $cmd = $cmd -replace "^(?i)\s*/repadmin\b", "repadmin" } - if ($server -and $cmd -match "(?i)\brepadmin\b" -and $cmd -match "(?i)\bsyncall\b" -and $cmd -notmatch "\{server\}") { - $cmd = $cmd -replace "(?i)\bsyncall\b", "syncall $server" + if ($UseRemote -and $cmd -match "(?i)\brepadmin\b" -and $cmd -match "(?i)\bsyncall\b") { + $remoteCmd = [regex]::Replace($cmd, "(?i)\\brepadmin\\s+/syncall\\s+\\S+", "repadmin /syncall") + & $Log "Replication (remote): $server -> $remoteCmd" + try { + Invoke-Command -ComputerName $server -ScriptBlock { param($c) & $env:ComSpec /c $c } -ArgumentList $remoteCmd | + ForEach-Object { & $Log $_ } + } catch { + & $Log "Replication error on $server: $($_.Exception.Message)" + } + continue + } + if (-not $usesToken -and $server -and $cmd -match "(?i)\brepadmin\b" -and $cmd -match "(?i)\bsyncall\b") { + if ($cmd -notmatch "(?i)\\bsyncall\\s+\\S+") { + $cmd = $cmd -replace "(?i)\\bsyncall\\b", "syncall $server" + } } if ([string]::IsNullOrWhiteSpace($cmd)) { continue } & $Log "Replication: $cmd" @@ -597,7 +612,18 @@ $y += 70 + $gap Add-Label "Replication command ({server} optional)" $xLabel $y $labelWidth $rowHeight $replicationCmdBox = Add-TextBox $xInput $y $inputWidth $rowHeight $false $replicationCmdBox.Text = "repadmin /syncall {server} /AdeP" -$y += $rowHeight + ($gap * 2) +$y += $rowHeight + $gap + +Add-Label "Replication wait (seconds)" $xLabel $y $labelWidth $rowHeight +$replicationDelayBox = Add-TextBox $xInput $y $inputWidth $rowHeight $false +$replicationDelayBox.Text = "30" +$y += $rowHeight + $gap + +$replicationRemoteBox = Add-CheckBox "Run repadmin remotely (PowerShell)" $xInput $y $inputWidth $rowHeight +$replicationRemoteBox.Checked = $true +$y += $rowHeight + $gap + +$y += $gap Add-SectionHeader "ACME / Output" Add-Label "WACS path" $xLabel $y $labelWidth $rowHeight @@ -705,6 +731,8 @@ function Update-ReplicationUI { $replicationFromSelectedBtn.Enabled = $enabled $primaryFromSelectedBtn.Enabled = $enabled $replicationCmdBox.Enabled = $enabled + $replicationDelayBox.Enabled = $enabled + $replicationRemoteBox.Enabled = $enabled $dnsListBox.Enabled = $enabled } @@ -725,6 +753,16 @@ function Update-CertGenerationUI { $validationPortBox.Enabled = -not $disabled } +function Update-ZoneFromHostInput { + $hostList = @(Split-List $hostsBox.Text) + if ($hostList.Count -eq 0) { return } + $zoneGuess = Get-CommonZoneFromHosts -Hosts $hostList + if (-not [string]::IsNullOrWhiteSpace($zoneGuess) -and $zoneBox.Text -ne $zoneGuess) { + $zoneBox.Text = $zoneGuess + & $logAction "Default DNS zone set to $zoneGuess (from hostnames)." + } +} + $loadedDefaults = Load-Defaults if ($loadedDefaults) { $value = Get-DefaultValue -Defaults $loadedDefaults -Name "DefaultZone" @@ -745,6 +783,12 @@ if ($loadedDefaults) { $value = Get-DefaultValue -Defaults $loadedDefaults -Name "ReplicationEnabled" if ($null -ne $value) { $replicationEnabledBox.Checked = [bool]$value } + $value = Get-DefaultValue -Defaults $loadedDefaults -Name "ReplicationDelaySeconds" + if ($null -ne $value) { $replicationDelayBox.Text = $value.ToString() } + + $value = Get-DefaultValue -Defaults $loadedDefaults -Name "ReplicationRemote" + if ($null -ne $value) { $replicationRemoteBox.Checked = [bool]$value } + $value = Get-DefaultValue -Defaults $loadedDefaults -Name "WacsPath" if (-not [string]::IsNullOrWhiteSpace($value)) { $wacsPathBox.Text = $value } @@ -817,6 +861,8 @@ function Apply-Layout { $replicationFromSelectedBtn.Left = $xInput + $inputWidthCalc - ((2 * $buttonWidth) + $buttonGap) $primaryFromSelectedBtn.Left = $xInput + $inputWidthCalc - $buttonWidth $replicationCmdBox.Width = $inputWidthCalc + $replicationDelayBox.Width = $inputWidthCalc + $replicationRemoteBox.Width = $inputWidthCalc $wacsPathBox.Width = $inputWidthCalc $outputTypeBox.Width = $inputWidthCalc $outputPathBox.Width = $inputWidthCalc @@ -954,6 +1000,10 @@ $outputTypeBox.Add_SelectedIndexChanged({ Update-OutputTypeUI }) +$hostsBox.Add_TextChanged({ + Update-ZoneFromHostInput +}) + $disableCertsBox.Add_CheckedChanged({ Update-CertGenerationUI }) @@ -966,6 +1016,8 @@ $saveDefaultsBtn.Add_Click({ ReplicationTargets = $replicationTargetsBox.Text ReplicationCommand = $replicationCmdBox.Text ReplicationEnabled = $replicationEnabledBox.Checked + ReplicationDelaySeconds = $replicationDelayBox.Text + ReplicationRemote = $replicationRemoteBox.Checked WacsPath = $wacsPathBox.Text OutputType = $outputTypeBox.SelectedItem.ToString() OutputPath = $outputPathBox.Text @@ -1034,6 +1086,13 @@ $runBtn.Add_Click({ } if ($replicationEnabledBox.Checked) { + $replicationDelaySeconds = 0 + $delayRaw = $replicationDelayBox.Text.Trim() + if (-not [string]::IsNullOrWhiteSpace($delayRaw)) { + if (-not [int]::TryParse($delayRaw, [ref]$replicationDelaySeconds) -or $replicationDelaySeconds -lt 0) { + throw "Replication wait seconds must be a non-negative integer." + } + } if ($selectedReplicationTargets.Count -gt 0) { $replicationTargets = $selectedReplicationTargets } else { @@ -1043,7 +1102,11 @@ $runBtn.Add_Click({ & $logAction "Replication targets empty; using primary DNS server $dnsServer." } } - Invoke-Replication -Servers $replicationTargets -Command $replicationCmdBox.Text -Log $logAction + Invoke-Replication -Servers $replicationTargets -Command $replicationCmdBox.Text -UseRemote $replicationRemoteBox.Checked -Log $logAction + if ($replicationDelaySeconds -gt 0) { + & $logAction "Waiting $replicationDelaySeconds seconds for replication." + Start-Sleep -Seconds $replicationDelaySeconds + } } else { & $logAction "Replication disabled." }