Add INF CSR-only generation option

This commit is contained in:
2026-01-30 12:49:36 +13:00
parent c545ae6d48
commit ad735ff4aa

108
certy.ps1
View File

@@ -279,9 +279,10 @@ function Remove-InfSubjectLines {
function Save-SanitizedInf {
param(
[string]$FileName,
[string[]]$Lines
[string[]]$Lines,
[string]$Subdir = "inf-sanitized"
)
$dir = Join-Path $env:ProgramData "Certy\\inf-sanitized"
$dir = Join-Path $env:ProgramData ("Certy\\" + $Subdir)
if (-not (Test-Path -Path $dir -PathType Container)) {
New-Item -Path $dir -ItemType Directory -Force | Out-Null
}
@@ -290,6 +291,36 @@ function Save-SanitizedInf {
return $outPath
}
function Sanitize-InfSubjectForCsr {
param([string[]]$Lines)
$updated = $false
$output = foreach ($line in $Lines) {
if ($line -match '(?i)^\s*subject\s*=\s*(.+)$') {
$value = $Matches[1].Trim()
$value = $value.Trim('"')
$parts = $value -split '\s*,\s*' | Where-Object { $_ }
$kept = @()
foreach ($part in $parts) {
if ($part -match '^(?i)OU\s*=') { continue }
$kept += $part.Trim()
}
if ($kept.Count -gt 0) {
$updated = $true
"Subject = `"$($kept -join ', ')`""
} else {
$updated = $true
continue
}
} else {
$line
}
}
return [pscustomobject]@{
Lines = $output
Updated = $updated
}
}
function Resolve-HostEntry {
param(
[string]$Name,
@@ -784,6 +815,17 @@ $panel.Controls.Add($infImportBtn)
Style-ButtonSecondary $infImportBtn
$y += $rowHeight + $gap
$infCsrOnlyBox = Add-CheckBox "Generate CSR from INF only (skip WACS)" $xInput $y $inputWidth $rowHeight
$infCsrOnlyBox.Checked = $false
$y += $rowHeight + $gap
$infCsrOutputLabel = Add-Label "CSR output folder" $xLabel $y $labelWidth $rowHeight
$infCsrOutputBox = Add-TextBox $xInput $y $inputWidth $rowHeight $false
$infCsrOutputBox.Text = "C:\ProgramData\Certy\csr-output"
$infCsrOutputLabel.Enabled = $false
$infCsrOutputBox.Enabled = $false
$y += $rowHeight + $gap
$useFqdnBox = Add-CheckBox "Input contains FQDNs (otherwise default zone is appended)" $xInput $y $inputWidth $rowHeight
$y += $rowHeight + $gap
@@ -1109,7 +1151,8 @@ function Show-HelpDialog {
$optY = $stepY + 36
$options = @(
"Turn off cert generation (DNS-only mode) to add DNS now and generate certs later.",
"Disable DNS replication if records already point correctly and you only need a renewal."
"Disable DNS replication if records already point correctly and you only need a renewal.",
"Generate CSR from INF only to produce .req files without running WACS."
)
foreach ($opt in $options) {
$bullet = New-Object System.Windows.Forms.Label
@@ -1154,7 +1197,7 @@ function Update-ReplicationUI {
}
function Update-CertGenerationUI {
$disabled = $disableCertsBox.Checked
$disabled = $disableCertsBox.Checked -or $infCsrOnlyBox.Checked
$perHostBox.Enabled = -not $disabled
$wacsPathBox.Enabled = -not $disabled
@@ -1167,6 +1210,14 @@ function Update-CertGenerationUI {
$validationPortBox.Enabled = -not $disabled
}
function Update-InfCsrUI {
$enabled = $infCsrOnlyBox.Checked
$infCsrOutputLabel.Enabled = $enabled
$infCsrOutputBox.Enabled = $enabled
}
Update-InfCsrUI
function Update-ZoneFromHostInput {
$hostList = @(Split-List $hostsBox.Text)
if ($hostList.Count -eq 0) { return }
@@ -1240,9 +1291,19 @@ if ($loadedDefaults) {
if (-not [string]::IsNullOrWhiteSpace($value)) { $outputTypeBox.SelectedItem = $value }
if (-not $outputTypeBox.SelectedItem) { $outputTypeBox.SelectedIndex = 0 }
$value = Get-DefaultValue -Defaults $loadedDefaults -Name "InfFolder"
if (-not [string]::IsNullOrWhiteSpace($value)) { $infFolderBox.Text = $value }
$value = Get-DefaultValue -Defaults $loadedDefaults -Name "InfCsrOnly"
if ($null -ne $value) { $infCsrOnlyBox.Checked = [bool]$value }
$value = Get-DefaultValue -Defaults $loadedDefaults -Name "InfCsrOutput"
if (-not [string]::IsNullOrWhiteSpace($value)) { $infCsrOutputBox.Text = $value }
Update-OutputTypeUI
if (Test-Path function:Update-ReplicationUI) { Update-ReplicationUI }
Update-CertGenerationUI
Update-InfCsrUI
& $logAction "Defaults loaded from $(Get-DefaultsPath)."
}
@@ -1269,6 +1330,8 @@ function Apply-Layout {
$infFolderBox.Width = $inputWidthCalc - ((2 * $buttonWidth) + $buttonGap)
$infBrowseBtn.Left = $xInput + $inputWidthCalc - ((2 * $buttonWidth) + $buttonGap)
$infImportBtn.Left = $xInput + $inputWidthCalc - $buttonWidth
$infCsrOutputBox.Width = $inputWidthCalc
$infCsrOnlyBox.Width = $inputWidthCalc
$zoneBox.Width = $inputWidthCalc
$ipBox.Width = $inputWidthCalc - ($buttonWidth + $buttonGap)
$ipRefreshBtn.Left = $xInput + $inputWidthCalc - $buttonWidth
@@ -1402,8 +1465,10 @@ $infImportBtn.Add_Click({
$lines = Get-Content -Path $infFile.FullName
$hosts = @(Get-HostsFromInfLines -Lines $lines)
$sanitize = Remove-InfSubjectLines -Lines $lines
$sanitizedPath = Save-SanitizedInf -FileName $infFile.Name -Lines $sanitize.Lines
$sanitizedPath = Save-SanitizedInf -FileName $infFile.Name -Lines $sanitize.Lines -Subdir "inf-sanitized"
if ($sanitize.Removed) { $subjectRemovedCount++ }
$csrSanitize = Sanitize-InfSubjectForCsr -Lines $lines
$csrInfPath = Save-SanitizedInf -FileName $infFile.Name -Lines $csrSanitize.Lines -Subdir "inf-csr"
if ($hosts.Count -eq 0) {
& $logAction "INF $($infFile.Name): no hostnames detected."
@@ -1414,6 +1479,7 @@ $infImportBtn.Add_Click({
File = $infFile.FullName
Hosts = $hosts
Sanitized = $sanitizedPath
CsrInf = $csrInfPath
}
$infHosts += $hosts
}
@@ -1512,6 +1578,11 @@ $disableCertsBox.Add_CheckedChanged({
Update-CertGenerationUI
})
$infCsrOnlyBox.Add_CheckedChanged({
Update-CertGenerationUI
Update-InfCsrUI
})
$saveDefaultsBtn.Add_Click({
$defaults = [pscustomobject]@{
DefaultZone = $zoneBox.Text
@@ -1534,6 +1605,9 @@ $saveDefaultsBtn.Add_Click({
Verbose = $verboseBox.Checked
PerHostCerts = $perHostBox.Checked
DisableCertGeneration = $disableCertsBox.Checked
InfFolder = $infFolderBox.Text
InfCsrOnly = $infCsrOnlyBox.Checked
InfCsrOutput = $infCsrOutputBox.Text
}
Save-Defaults -Defaults $defaults
& $logAction "Defaults saved to $(Get-DefaultsPath)."
@@ -1635,7 +1709,29 @@ $runBtn.Add_Click({
& $logAction "Replication disabled."
}
if ($disableCertsBox.Checked) {
if ($infCsrOnlyBox.Checked) {
if (-not $script:infRequests -or $script:infRequests.Count -eq 0) {
throw "INF CSR generation enabled, but no INF files were imported."
}
$csrOutputDir = $infCsrOutputBox.Text.Trim()
if (-not $csrOutputDir) { throw "CSR output folder is required." }
if (-not (Test-Path -Path $csrOutputDir -PathType Container)) {
New-Item -Path $csrOutputDir -ItemType Directory -Force | Out-Null
}
foreach ($req in $script:infRequests) {
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($req.File)
$csrPath = Join-Path $csrOutputDir ($baseName + ".req")
if (Test-Path -Path $csrPath) {
$csrPath = Join-Path $csrOutputDir ($baseName + "-" + (Get-Date -Format "yyyyMMddHHmmss") + ".req")
}
$infPath = if ($req.CsrInf) { $req.CsrInf } else { $req.File }
& $logAction "Generating CSR from $([System.IO.Path]::GetFileName($infPath)) -> $csrPath"
$output = & certreq.exe -new $infPath $csrPath 2>&1
foreach ($line in $output) {
& $logAction $line
}
}
} elseif ($disableCertsBox.Checked) {
& $logAction "Cert generation disabled; DNS updates/replication only."
} else {
$wacsPath = $wacsPathBox.Text.Trim()