<# .SYNOPSIS Exports the PESCO internal CA certificates from this PC's Windows certificate stores to a PEM bundle and copies it to docker-1 for the Packet Station stacks. .DESCRIPTION Run on a domain-joined PC. It reads the LocalMachine and CurrentUser Root and CA stores, keeps every unexpired certificate whose subject matches -SubjectMatch (default PESCO), writes them as one PEM file with a comment line per certificate, and copies the file to the remote path with scp. The file holds public certificates only; nothing secret. The stacks point LDAP_CA_BUNDLE and SMTP_CA_BUNDLE at this file. MFILES_CA_BUNDLE stays unset because M-Files uses a public certificate. .EXAMPLE .\scripts\Export-PescoCaBundle.ps1 Writes the bundle and copies it to spencerm@192.168.101.12:~/packetstation/test/ca/pesco-ca.pem .EXAMPLE .\scripts\Export-PescoCaBundle.ps1 -Remote 'spencerm@192.168.101.12:/etc/packetstation/ca/pesco-ca.pem' .EXAMPLE .\scripts\Export-PescoCaBundle.ps1 -NoCopy -OutFile C:\temp\pesco-ca.pem #> [CmdletBinding()] param( # Regex matched against each certificate subject. [string]$SubjectMatch = 'PESCO', # Local PEM file to write. [string]$OutFile = (Join-Path $env:TEMP 'pesco-ca.pem'), # scp destination. Needs an SSH key that works without a prompt. [string]$Remote = 'spencerm@192.168.101.12:~/packetstation/test/ca/pesco-ca.pem', # Write the file only; do not copy it. [switch]$NoCopy ) $ErrorActionPreference = 'Stop' $now = Get-Date $stores = 'Cert:\LocalMachine\Root', 'Cert:\LocalMachine\CA', 'Cert:\CurrentUser\Root', 'Cert:\CurrentUser\CA' $certs = Get-ChildItem $stores | Where-Object { $_.Subject -match $SubjectMatch -and $_.NotAfter -gt $now } | Sort-Object Thumbprint -Unique if (-not $certs) { throw "No unexpired certificate with subject matching '$SubjectMatch' in the Root or CA stores." } $sb = New-Object System.Text.StringBuilder foreach ($c in $certs) { $sig = $c.SignatureAlgorithm.FriendlyName [void]$sb.AppendLine("# $($c.Subject) | issued by $($c.Issuer) | expires $($c.NotAfter.ToString('yyyy-MM-dd')) | $sig") [void]$sb.AppendLine('-----BEGIN CERTIFICATE-----') [void]$sb.AppendLine([Convert]::ToBase64String($c.RawData, 'InsertLineBreaks')) [void]$sb.AppendLine('-----END CERTIFICATE-----') Write-Host (" {0} expires {1} {2}" -f $c.Subject, $c.NotAfter.ToString('yyyy-MM-dd'), $sig) if ($sig -match 'sha1') { Write-Warning "$($c.Subject) is SHA-1 signed. OpenSSL 3 refuses SHA-1 chains at its default security level; see docs/DEPLOY.md." } } # LF line endings so the file is clean on Linux. [IO.File]::WriteAllText($OutFile, $sb.ToString().Replace("`r`n", "`n")) Write-Host "Wrote $OutFile ($($certs.Count) certificates)" if ($NoCopy) { return } & scp -o BatchMode=yes $OutFile $Remote if ($LASTEXITCODE -ne 0) { throw "scp to $Remote failed (exit $LASTEXITCODE)" } Write-Host "Copied to $Remote"