$OutputDir =
"C:\eclipsys\oci_cert_renewal\output"
$CertifyExe =
"C:\Program Files\CertifyTheWeb\certify.exe"
$OpenSSL =
"C:\Program Files\OpenSSL-Win64\bin\openssl.exe"
$CertSubjectMatch =
"*reports.eclipsys.ca*"
$PfxPassword =
"
"
$OciRegion =
"ca-toronto-1"
$OciCertificateId =
"ocid1.certificate.oc1.ca-toronto-1.<...>"
$SecurityListId =
"ocid1.securitylist.oc1.ca-toronto-1.<...>"
$BackupIngressJson =
"C:\eclipsys\oci_cert_renewal\uleth_ingress_rules.json"
$OpenIngressJson =
"C:\eclipsys\oci_cert_renewal\open_port80_ingress.json"
$CloseIngressJson =
"C:\eclipsys\oci_cert_renewal\close_port80_ingress.json"
$PfxFile =
"
$OutputDir
\fastcert.pfx"
$CertPem =
"
$OutputDir
\certificate.pem"
$KeyProtected =
"
$OutputDir
\private_key_nonrsa.pem"
$KeyPem =
"
$OutputDir
\privatekey.pem"
$CaPem =
"
$OutputDir
\eclipsys_cert_ca.crt"
$RootPem =
"
$OutputDir
\eclipsys_cert_root.crt"
$FullChainPem =
"
$OutputDir
\certificatechain.pem"
$LogPath =
"
$OutputDir
\cert_renewal.log
Purpose: Centralize configuration so values aren’t scattered throughout the script.
Backup current ingress, then open Port 80 (ACME HTTP-01)
oci network security-list get
`
--security-list-id
$SecurityListId
`
--query data.'ingress-security-rules'
`
--output json >
$BackupIngressJson
oci network security-list update
`
--security-list-id
$SecurityListId
`
--ingress-security-rules file://
$OpenIngressJson
`
--force
What it does: Backs up current rules and temporarily opens TCP/80 to complete the ACME challenge.
Renew with CertifyTheWeb (CTW) and log output
Start-Process -FilePath
$CertifyExe
`
-ArgumentList "renew --force-renew-all --verbose
"
`
-RedirectStandardOutput
$LogPath
`
-Wait -NoNewWindow
What it does: Forces a renewal and captures verbose logs for audit/troubleshooting.
Export the newest matching certificate (PFX) from the Windows store
New-Item -Path
$OutputDir
-ItemType Directory -Force | Out-Null
$cert
= Get-ChildItem Cert:\LocalMachine\My |
Where-Object {
$_
.Subject -like
$CertSubjectMatch
} |
Sort-Object NotAfter -Descending | Select-Object -First 1
if (-not
$cert
) { throw "No certificate found
for
$CertSubjectMatch
" }
$bytes
=
$cert
.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pfx,
$PfxPassword
)
[System.IO.File]::WriteAllBytes(
$PfxFile
,
$bytes
)
What it does: Selects the most recent matching cert and exports it as PFX (includes private key).
OpenSSL: split PFX → private key + leaf cert, and capture CA
&
$OpenSSL
pkcs12 -in
$PfxFile
-nocerts -out
$KeyProtected
-passin pass:
$PfxPassword
-passout pass:
$PfxPassword
&
$OpenSSL
rsa -in
$KeyProtected
-out
$KeyPem
-passin pass:
$PfxPassword
&
$OpenSSL
pkcs12 -in
$PfxFile
-clcerts -nokeys -out
$CertPem
-passin pass:
$PfxPassword
&
$OpenSSL
pkcs12 -in
$PfxFile
-cacerts -nokeys -out
$CaPem
-passin pass:
$PfxPassword
What it does: Extracts private key, leaf certificate, and intermediate(s).
$issuer
= (&
$OpenSSL
x509 -in
$CertPem
-noout -issuer)
$intermediateURL
= switch -Regex (
$issuer
) {
"R13
" { "https://letsencrypt.org/certs/
2024/r13.pem
" ; break }
"R12
" { "https://letsencrypt.org/certs/
2024/r12.pem
" ; break }
"R11
" { "https://letsencrypt.org/certs/
2024/r11.pem
" ; break }
default { "https://letsencrypt.org/certs/
2024/r10.pem
" }
}
$rootURL
= "https://letsencrypt.org/certs/isrgrootx1.pem
"
Invoke-WebRequest -Uri
$intermediateURL
-OutFile
$CaPem
Invoke-WebRequest -Uri
$rootURL
-OutFile
$RootPem
Get-Content
$CaPem
,
$RootPem
| Set-Content
$FullChainPem
What it does: Ensures you always include the correct intermediate and root for a valid trust chain.