Improve Certy UI and defaults
This commit is contained in:
173
certy.ps1
173
certy.ps1
@@ -69,6 +69,33 @@ function Get-FilePreview {
|
||||
}
|
||||
}
|
||||
|
||||
function Get-DefaultsPath {
|
||||
$dir = Join-Path $env:ProgramData "Certy"
|
||||
return Join-Path $dir "defaults.json"
|
||||
}
|
||||
|
||||
function Load-Defaults {
|
||||
$path = Get-DefaultsPath
|
||||
if (-not (Test-Path -Path $path -PathType Leaf)) { return $null }
|
||||
try {
|
||||
$raw = Get-Content -Path $path -Raw -ErrorAction Stop
|
||||
return $raw | ConvertFrom-Json
|
||||
} catch {
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function Save-Defaults {
|
||||
param([pscustomobject]$Defaults)
|
||||
$path = Get-DefaultsPath
|
||||
$dir = Split-Path -Path $path -Parent
|
||||
if (-not (Test-Path -Path $dir -PathType Container)) {
|
||||
New-Item -Path $dir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
$json = $Defaults | ConvertTo-Json -Depth 6
|
||||
Set-Content -Path $path -Value $json -Encoding ascii
|
||||
}
|
||||
|
||||
function Resolve-HostEntry {
|
||||
param(
|
||||
[string]$Name,
|
||||
@@ -182,7 +209,7 @@ function Invoke-Replication {
|
||||
function Invoke-Wacs {
|
||||
param(
|
||||
[string]$WacsPath,
|
||||
[string]$HostFqdn,
|
||||
[string[]]$HostFqdns,
|
||||
[string]$OutputType,
|
||||
[string]$OutputPath,
|
||||
[string]$PfxPassword,
|
||||
@@ -193,7 +220,12 @@ function Invoke-Wacs {
|
||||
[scriptblock]$Log
|
||||
)
|
||||
|
||||
$args = @("--target", "manual", "--host", $HostFqdn)
|
||||
$args = @("--target", "manual")
|
||||
foreach ($host in $HostFqdns) {
|
||||
if (-not [string]::IsNullOrWhiteSpace($host)) {
|
||||
$args += @("--host", $host)
|
||||
}
|
||||
}
|
||||
|
||||
if ($OutputType -eq "PEM") {
|
||||
$args += @("--store", "pemfiles", "--pemfilespath", $OutputPath)
|
||||
@@ -255,8 +287,9 @@ $rowHeight = 24
|
||||
$gap = 8
|
||||
$leftMargin = 20
|
||||
$rightMargin = 20
|
||||
$buttonWidth = 80
|
||||
$buttonGap = 8
|
||||
$buttonWidth = 110
|
||||
$buttonGap = 10
|
||||
$actionButtonWidth = 130
|
||||
|
||||
$navTitle = New-Object System.Windows.Forms.Label
|
||||
$navTitle.Text = "CERTY"
|
||||
@@ -400,38 +433,38 @@ $hostsBox = Add-TextBox $xInput $y $inputWidth 100 $true
|
||||
$y += 100 + $gap
|
||||
|
||||
Add-Label "Hostnames file (optional)" $xLabel $y $labelWidth $rowHeight
|
||||
$fileBox = Add-TextBox $xInput $y ($inputWidth - 90) $rowHeight $false
|
||||
$fileBox = Add-TextBox $xInput $y ($inputWidth - ($buttonWidth + $buttonGap)) $rowHeight $false
|
||||
$browseBtn = New-Object System.Windows.Forms.Button
|
||||
$browseBtn.Text = "Browse"
|
||||
$browseBtn.Location = [System.Drawing.Point]::new(($xInput + $inputWidth - $buttonWidth), ($y - 1))
|
||||
$browseBtn.Size = [System.Drawing.Size]::new(80, 26)
|
||||
$browseBtn.Size = [System.Drawing.Size]::new($buttonWidth, 26)
|
||||
$panel.Controls.Add($browseBtn)
|
||||
Style-ButtonSecondary $browseBtn
|
||||
$y += $rowHeight + $gap
|
||||
|
||||
Add-Label "File preview (first 200 lines)" $xLabel $y $labelWidth $rowHeight
|
||||
$filePreviewBox = Add-TextBox $xInput $y ($inputWidth - 90) 80 $true
|
||||
$filePreviewBox = Add-TextBox $xInput $y ($inputWidth - ($buttonWidth + $buttonGap)) 80 $true
|
||||
$filePreviewBox.ReadOnly = $true
|
||||
$filePreviewBtn = New-Object System.Windows.Forms.Button
|
||||
$filePreviewBtn.Text = "Preview"
|
||||
$filePreviewBtn.Location = [System.Drawing.Point]::new(($xInput + $inputWidth - $buttonWidth), ($y - 1))
|
||||
$filePreviewBtn.Size = [System.Drawing.Size]::new(80, 26)
|
||||
$filePreviewBtn.Size = [System.Drawing.Size]::new($buttonWidth, 26)
|
||||
$panel.Controls.Add($filePreviewBtn)
|
||||
Style-ButtonSecondary $filePreviewBtn
|
||||
$y += 82 + $gap
|
||||
|
||||
$csrLabel = Add-Label "CSR folder (optional)" $xLabel $y $labelWidth $rowHeight
|
||||
$csrFolderBox = Add-TextBox $xInput $y ($inputWidth - 180) $rowHeight $false
|
||||
$csrFolderBox = Add-TextBox $xInput $y ($inputWidth - ((2 * $buttonWidth) + $buttonGap)) $rowHeight $false
|
||||
$csrBrowseBtn = New-Object System.Windows.Forms.Button
|
||||
$csrBrowseBtn.Text = "Browse"
|
||||
$csrBrowseBtn.Location = [System.Drawing.Point]::new(($xInput + $inputWidth - (2 * $buttonWidth + $buttonGap)), ($y - 1))
|
||||
$csrBrowseBtn.Size = [System.Drawing.Size]::new(80, 26)
|
||||
$csrBrowseBtn.Size = [System.Drawing.Size]::new($buttonWidth, 26)
|
||||
$panel.Controls.Add($csrBrowseBtn)
|
||||
Style-ButtonSecondary $csrBrowseBtn
|
||||
$csrImportBtn = New-Object System.Windows.Forms.Button
|
||||
$csrImportBtn.Text = "Import CSR"
|
||||
$csrImportBtn.Location = [System.Drawing.Point]::new(($xInput + $inputWidth - $buttonWidth), ($y - 1))
|
||||
$csrImportBtn.Size = [System.Drawing.Size]::new(80, 26)
|
||||
$csrImportBtn.Size = [System.Drawing.Size]::new($buttonWidth, 26)
|
||||
$panel.Controls.Add($csrImportBtn)
|
||||
Style-ButtonSecondary $csrImportBtn
|
||||
$y += $rowHeight + $gap
|
||||
@@ -446,12 +479,12 @@ $zoneBox.Text = "record.domain.govt.nz"
|
||||
$y += $rowHeight + $gap
|
||||
|
||||
Add-Label "Target IPv4 for A records" $xLabel $y $labelWidth $rowHeight
|
||||
$ipBox = Add-TextBox $xInput $y ($inputWidth - 90) $rowHeight $false
|
||||
$ipBox = Add-TextBox $xInput $y ($inputWidth - ($buttonWidth + $buttonGap)) $rowHeight $false
|
||||
$ipBox.Text = Get-LocalIpv4
|
||||
$ipRefreshBtn = New-Object System.Windows.Forms.Button
|
||||
$ipRefreshBtn.Text = "Use Local"
|
||||
$ipRefreshBtn.Location = [System.Drawing.Point]::new(($xInput + $inputWidth - $buttonWidth), ($y - 1))
|
||||
$ipRefreshBtn.Size = [System.Drawing.Size]::new(80, 26)
|
||||
$ipRefreshBtn.Size = [System.Drawing.Size]::new($buttonWidth, 26)
|
||||
$panel.Controls.Add($ipRefreshBtn)
|
||||
Style-ButtonSecondary $ipRefreshBtn
|
||||
$y += $rowHeight + $gap
|
||||
@@ -459,7 +492,7 @@ $y += $rowHeight + $gap
|
||||
Add-Label "Primary DNS server" $xLabel $y $labelWidth $rowHeight
|
||||
$dnsServerBox = New-Object System.Windows.Forms.ComboBox
|
||||
$dnsServerBox.Location = [System.Drawing.Point]::new($xInput, $y)
|
||||
$dnsServerBox.Size = [System.Drawing.Size]::new(($inputWidth - 90), $rowHeight)
|
||||
$dnsServerBox.Size = [System.Drawing.Size]::new(($inputWidth - ($buttonWidth + $buttonGap)), $rowHeight)
|
||||
$dnsServerBox.DropDownStyle = "DropDown"
|
||||
$dnsServerBox.Text = "DC01.example.local"
|
||||
$dnsServerBox.FlatStyle = "Flat"
|
||||
@@ -469,7 +502,7 @@ $panel.Controls.Add($dnsServerBox)
|
||||
$dnsScanBtn = New-Object System.Windows.Forms.Button
|
||||
$dnsScanBtn.Text = "Scan"
|
||||
$dnsScanBtn.Location = [System.Drawing.Point]::new(($xInput + $inputWidth - $buttonWidth), ($y - 1))
|
||||
$dnsScanBtn.Size = [System.Drawing.Size]::new(80, 26)
|
||||
$dnsScanBtn.Size = [System.Drawing.Size]::new($buttonWidth, 26)
|
||||
$panel.Controls.Add($dnsScanBtn)
|
||||
Style-ButtonSecondary $dnsScanBtn
|
||||
$y += $rowHeight + $gap
|
||||
@@ -486,17 +519,17 @@ $panel.Controls.Add($dnsListBox)
|
||||
$y += 82 + $gap
|
||||
|
||||
Add-Label "Replication targets (one per line)" $xLabel $y $labelWidth $rowHeight
|
||||
$replicationTargetsBox = Add-TextBox $xInput $y ($inputWidth - 180) 70 $true
|
||||
$replicationTargetsBox = Add-TextBox $xInput $y ($inputWidth - ((2 * $buttonWidth) + $buttonGap)) 70 $true
|
||||
$replicationFromSelectedBtn = New-Object System.Windows.Forms.Button
|
||||
$replicationFromSelectedBtn.Text = "Use Selected"
|
||||
$replicationFromSelectedBtn.Location = [System.Drawing.Point]::new(($xInput + $inputWidth - (2 * $buttonWidth + $buttonGap)), ($y - 1))
|
||||
$replicationFromSelectedBtn.Size = [System.Drawing.Size]::new(80, 26)
|
||||
$replicationFromSelectedBtn.Size = [System.Drawing.Size]::new($buttonWidth, 26)
|
||||
$panel.Controls.Add($replicationFromSelectedBtn)
|
||||
Style-ButtonSecondary $replicationFromSelectedBtn
|
||||
$primaryFromSelectedBtn = New-Object System.Windows.Forms.Button
|
||||
$primaryFromSelectedBtn.Text = "Use Primary"
|
||||
$primaryFromSelectedBtn.Location = [System.Drawing.Point]::new(($xInput + $inputWidth - $buttonWidth), ($y - 1))
|
||||
$primaryFromSelectedBtn.Size = [System.Drawing.Size]::new(80, 26)
|
||||
$primaryFromSelectedBtn.Size = [System.Drawing.Size]::new($buttonWidth, 26)
|
||||
$panel.Controls.Add($primaryFromSelectedBtn)
|
||||
Style-ButtonSecondary $primaryFromSelectedBtn
|
||||
$y += 70 + $gap
|
||||
@@ -554,6 +587,7 @@ $y += $rowHeight + $gap
|
||||
Add-SectionHeader "Run"
|
||||
$verboseBox = Add-CheckBox "Verbose" $xInput $y 120 $rowHeight
|
||||
$runWacsBox = Add-CheckBox "Run WACS after DNS update" ($xInput + 140) $y 260 $rowHeight
|
||||
$perHostBox = Add-CheckBox "One cert per host" ($xInput + 430) $y 180 $rowHeight
|
||||
$runWacsBox.Checked = $true
|
||||
$y += $rowHeight + ($gap * 2)
|
||||
|
||||
@@ -567,10 +601,17 @@ Style-ButtonPrimary $runBtn
|
||||
$clearBtn = New-Object System.Windows.Forms.Button
|
||||
$clearBtn.Text = "Clear Log"
|
||||
$clearBtn.Location = [System.Drawing.Point]::new(($xInput + 140), $y)
|
||||
$clearBtn.Size = [System.Drawing.Size]::new(120, 30)
|
||||
$clearBtn.Size = [System.Drawing.Size]::new($actionButtonWidth, 30)
|
||||
$panel.Controls.Add($clearBtn)
|
||||
Style-ButtonSecondary $clearBtn
|
||||
|
||||
$saveDefaultsBtn = New-Object System.Windows.Forms.Button
|
||||
$saveDefaultsBtn.Text = "Save Defaults"
|
||||
$saveDefaultsBtn.Location = [System.Drawing.Point]::new(($xInput + 140 + $actionButtonWidth + $buttonGap), $y)
|
||||
$saveDefaultsBtn.Size = [System.Drawing.Size]::new($actionButtonWidth, 30)
|
||||
$panel.Controls.Add($saveDefaultsBtn)
|
||||
Style-ButtonSecondary $saveDefaultsBtn
|
||||
|
||||
$y += 40
|
||||
Add-SectionHeader "Activity"
|
||||
Add-Label "Activity log" $xLabel $y $labelWidth $rowHeight
|
||||
@@ -583,6 +624,42 @@ $logAction = {
|
||||
$logBox.AppendText("[$timestamp] $Message`r`n")
|
||||
}
|
||||
|
||||
function Update-OutputTypeUI {
|
||||
if ($outputTypeBox.SelectedItem -eq "PEM") {
|
||||
$outputPathLabel.Text = "PEM output path"
|
||||
$pfxPasswordLabel.Visible = $false
|
||||
$pfxPasswordBox.Visible = $false
|
||||
$pfxPasswordBox.Text = ""
|
||||
} else {
|
||||
$outputPathLabel.Text = "PFX output path"
|
||||
$pfxPasswordLabel.Visible = $true
|
||||
$pfxPasswordBox.Visible = $true
|
||||
}
|
||||
}
|
||||
|
||||
$loadedDefaults = Load-Defaults
|
||||
if ($loadedDefaults) {
|
||||
if ($loadedDefaults.DefaultZone) { $zoneBox.Text = $loadedDefaults.DefaultZone }
|
||||
if ($loadedDefaults.TargetIp) { $ipBox.Text = $loadedDefaults.TargetIp }
|
||||
if ($loadedDefaults.DnsServer) { $dnsServerBox.Text = $loadedDefaults.DnsServer }
|
||||
if ($loadedDefaults.ReplicationTargets) { $replicationTargetsBox.Text = $loadedDefaults.ReplicationTargets }
|
||||
if ($loadedDefaults.ReplicationCommand) { $replicationCmdBox.Text = $loadedDefaults.ReplicationCommand }
|
||||
if ($loadedDefaults.WacsPath) { $wacsPathBox.Text = $loadedDefaults.WacsPath }
|
||||
if ($loadedDefaults.OutputPath) { $outputPathBox.Text = $loadedDefaults.OutputPath }
|
||||
if ($loadedDefaults.PfxPassword) { $pfxPasswordBox.Text = $loadedDefaults.PfxPassword }
|
||||
if ($loadedDefaults.BaseUri) { $baseUriBox.Text = $loadedDefaults.BaseUri }
|
||||
if ($loadedDefaults.Validation) { $validationBox.Text = $loadedDefaults.Validation }
|
||||
if ($loadedDefaults.ValidationPort) { $validationPortBox.Text = $loadedDefaults.ValidationPort }
|
||||
if ($null -ne $loadedDefaults.UseProvidedFqdn) { $useFqdnBox.Checked = [bool]$loadedDefaults.UseProvidedFqdn }
|
||||
if ($null -ne $loadedDefaults.RunWacs) { $runWacsBox.Checked = [bool]$loadedDefaults.RunWacs }
|
||||
if ($null -ne $loadedDefaults.Verbose) { $verboseBox.Checked = [bool]$loadedDefaults.Verbose }
|
||||
if ($null -ne $loadedDefaults.PerHostCerts) { $perHostBox.Checked = [bool]$loadedDefaults.PerHostCerts }
|
||||
if ($loadedDefaults.OutputType) { $outputTypeBox.SelectedItem = $loadedDefaults.OutputType }
|
||||
if (-not $outputTypeBox.SelectedItem) { $outputTypeBox.SelectedIndex = 0 }
|
||||
Update-OutputTypeUI
|
||||
& $logAction "Defaults loaded from $(Get-DefaultsPath)."
|
||||
}
|
||||
|
||||
function Apply-Layout {
|
||||
if ($panel.ClientSize.Width -le 0) { return }
|
||||
$contentWidth = $panel.ClientSize.Width - $leftMargin - $rightMargin
|
||||
@@ -620,6 +697,8 @@ function Apply-Layout {
|
||||
$validationBox.Width = $inputWidthCalc
|
||||
$validationPortBox.Width = $inputWidthCalc
|
||||
$logBox.Width = $inputWidthCalc
|
||||
$clearBtn.Left = $xInput + 140
|
||||
$saveDefaultsBtn.Left = $clearBtn.Left + $clearBtn.Width + $buttonGap
|
||||
}
|
||||
|
||||
$browseBtn.Add_Click({
|
||||
@@ -714,15 +793,32 @@ $primaryFromSelectedBtn.Add_Click({
|
||||
})
|
||||
|
||||
$outputTypeBox.Add_SelectedIndexChanged({
|
||||
if ($outputTypeBox.SelectedItem -eq "PEM") {
|
||||
$outputPathLabel.Text = "PEM output path"
|
||||
$pfxPasswordLabel.Visible = $false
|
||||
$pfxPasswordBox.Visible = $false
|
||||
$pfxPasswordBox.Text = ""
|
||||
} else {
|
||||
$outputPathLabel.Text = "PFX output path"
|
||||
$pfxPasswordLabel.Visible = $true
|
||||
$pfxPasswordBox.Visible = $true
|
||||
Update-OutputTypeUI
|
||||
})
|
||||
|
||||
$saveDefaultsBtn.Add_Click({
|
||||
$defaults = [pscustomobject]@{
|
||||
DefaultZone = $zoneBox.Text
|
||||
TargetIp = $ipBox.Text
|
||||
DnsServer = $dnsServerBox.Text
|
||||
ReplicationTargets = $replicationTargetsBox.Text
|
||||
ReplicationCommand = $replicationCmdBox.Text
|
||||
WacsPath = $wacsPathBox.Text
|
||||
OutputType = $outputTypeBox.SelectedItem.ToString()
|
||||
OutputPath = $outputPathBox.Text
|
||||
PfxPassword = $pfxPasswordBox.Text
|
||||
BaseUri = $baseUriBox.Text
|
||||
Validation = $validationBox.Text
|
||||
ValidationPort = $validationPortBox.Text
|
||||
UseProvidedFqdn = $useFqdnBox.Checked
|
||||
RunWacs = $runWacsBox.Checked
|
||||
Verbose = $verboseBox.Checked
|
||||
PerHostCerts = $perHostBox.Checked
|
||||
}
|
||||
Save-Defaults -Defaults $defaults
|
||||
& $logAction "Defaults saved to $(Get-DefaultsPath)."
|
||||
if (-not [string]::IsNullOrWhiteSpace($pfxPasswordBox.Text)) {
|
||||
& $logAction "Warning: PFX password is stored in plaintext."
|
||||
}
|
||||
})
|
||||
|
||||
@@ -785,10 +881,27 @@ $runBtn.Add_Click({
|
||||
if (-not (Test-Path -Path $wacsPath -PathType Leaf)) {
|
||||
throw "WACS not found at: $wacsPath"
|
||||
}
|
||||
foreach ($entry in $hostEntries) {
|
||||
if ($perHostBox.Checked) {
|
||||
foreach ($entry in $hostEntries) {
|
||||
& $logAction "Requesting certificate for $($entry.Fqdn)."
|
||||
Invoke-Wacs `
|
||||
-WacsPath $wacsPath `
|
||||
-HostFqdns @($entry.Fqdn) `
|
||||
-OutputType $outputType `
|
||||
-OutputPath $outputPath `
|
||||
-PfxPassword $pfxPasswordBox.Text `
|
||||
-BaseUri $baseUriBox.Text.Trim() `
|
||||
-Validation $validationBox.Text.Trim() `
|
||||
-ValidationPort $validationPortBox.Text.Trim() `
|
||||
-Verbose $verboseBox.Checked `
|
||||
-Log $logAction
|
||||
}
|
||||
} else {
|
||||
$hostList = $hostEntries | ForEach-Object { $_.Fqdn }
|
||||
& $logAction "Requesting one certificate with $($hostList.Count) hostname(s)."
|
||||
Invoke-Wacs `
|
||||
-WacsPath $wacsPath `
|
||||
-HostFqdn $entry.Fqdn `
|
||||
-HostFqdns $hostList `
|
||||
-OutputType $outputType `
|
||||
-OutputPath $outputPath `
|
||||
-PfxPassword $pfxPasswordBox.Text `
|
||||
|
||||
Reference in New Issue
Block a user