This will help automate the copy of the CRL from your offline root certificate authority that should offline and shutdown except for new certificate for the server and to create a new CRL.
This script can be run after the server is powered up and as this device should be in a workgroup then you will need to secure your credentials with an encrypted XML file as we do not want password in the script, once there operations have been completed you should shutdown your offline root certificate authority (as it should be offline)
Generate Encrypted XML credentials
Firstly, we need to get the credentials we are using for the copy to the web server in an XML file will can be done with these commands:
$credential = Get-Credential
$credential | Export-CliXml -Path "credentials.xml"
This will then give you a credentials.xml file that will contain your encrypted domain credentials that will be used later for the copy to the web servers.
Assumptions for this script
- The Offline Root Certificate server is running Windows
- The Offline Root Certificate server is in a workgroup
- You have Windows servers running IIS for hosting the CRL and other PKI files
- Your IIS hosted servers are in the domain and have a certain directory structure
- You have access to the Offline Root Certificate server (after it has been powered up)
- You have valid credentials for the web servers (that will stored in an encrypted XML file)
Script Process Flow
Then we need to understand the flow of the script which follows this path:
- Runs the command "certutil -crl" this will generate a new CRL file with a valid validity period
- Runs the command "certutil" to extract the name of the CA from the Name attribute stored as $crlName
- Obtain the generate folder from the folder C:\Windows\System32\certsrv\CertEnroll\$crlName.crl
- This file will then be copied to all the web servers defined in the script to the path in this instance \\$serverIP\c$\inetpub\pki\crl\$crlName.crl
- Script will report status and error and successes
Script : CRLRenew.ps1
# Define variables for web servers
$webServer1 = "10.22.555.77" # Primary web server
$webServer2 = "10.22.555.78" # Secondary web server
$credentialPath = "credentials.xml" # Path to your encrypted credentials file
# Enable verbose output
$VerbosePreference = "Continue"
Write-Verbose "Starting CRL distribution process..."
# Function to check certutil command success
function Test-CertutilSuccess {
param (
[string[]]$Output,
[string]$Command
)
$success = $Output | Select-String "Command completed successfully" -Quiet
if (-not $success) {
Write-Verbose "Failed : Command '$Command' did not complete successfully"
return $false
}
return $true
}
try {
# Step 1: Check if server is a CA and publish CRL
Write-Verbose "Publishing CRL using certutil -crl"
$crlPublish = certutil -crl
if (-not (Test-CertutilSuccess -Output $crlPublish -Command "certutil -crl")) {
Write-Verbose "Failed : This server is not a certificate authority"
exit 1
}
Write-Verbose "CRL publication completed successfully"
# Step 2: Get CRL name using certutil
Write-Verbose "Extracting CRL information using certutil"
$certOutput = certutil
if (-not (Test-CertutilSuccess -Output $certOutput -Command "certutil")) {
Write-Verbose "Failed : Could not retrieve certificate information"
exit 1
}
# Extract CRL name from output
$crlName = if ($certOutput -match 'Name:\s+"([^"]+)"') {
$matches[1]
Write-Verbose "CRL name extracted successfully: $($matches[1])"
} else {
Write-Verbose "Failed : Could not extract CRL name from certutil output"
exit 1
}
# Define source path
$sourcePath = "C:\Windows\System32\certsrv\CertEnroll\$crlName.crl"
Write-Verbose "Source path: $sourcePath"
# Verify source file exists
if (-not (Test-Path $sourcePath)) {
Write-Verbose "Failed : Source CRL file not found at: $sourcePath"
exit 1
}
Write-Verbose "Source CRL file verified successfully"
# Import encrypted credentials
Write-Verbose "Importing credentials from $credentialPath"
if (-not (Test-Path $credentialPath)) {
Write-Verbose "Failed : Credential file not found at: $credentialPath"
exit 1
}
try {
$credential = Import-CliXml -Path $credentialPath
Write-Verbose "Credentials imported successfully"
}
catch {
Write-Verbose "Failed : Could not import credentials from $credentialPath"
exit 1
}
# Function to copy CRL to web server
function Copy-CRLToServer {
param (
[string]$serverIP,
[string]$sourcePath,
[string]$crlName,
[System.Management.Automation.PSCredential]$credential
)
Write-Verbose "Processing server: $serverIP"
$driveName = "CRL_" + ($serverIP -replace '\.', '_')
$destination = "\\$serverIP\c$\inetpub\pki\crl\$crlName.crl"
try {
# Create PSDrive
Write-Verbose "Creating temporary PSDrive to $serverIP"
New-PSDrive -Name $driveName -PSProvider FileSystem -Root "\\$serverIP\c$" -Credential $credential -ErrorAction Stop | Out-Null
Write-Verbose "PSDrive created successfully"
# Create directory if it doesn't exist
$remoteDir = "$driveName`:\inetpub\pki\crl"
if (-not (Test-Path $remoteDir)) {
Write-Verbose "Creating directory: $remoteDir"
New-Item -Path $remoteDir -ItemType Directory -Force | Out-Null
Write-Verbose "Directory created successfully"
}
# Copy file
Write-Verbose "Copying CRL to $destination"
Copy-Item -Path $sourcePath -Destination $destination -Force
Write-Verbose "File copy completed"
# Verify copy
if (Test-Path "$remoteDir\$crlName.crl") {
Write-Verbose "Successfully verified CRL copy on $serverIP"
return $true
} else {
Write-Verbose "Failed : Could not verify CRL copy on $serverIP"
return $false
}
}
catch {
Write-Verbose "Failed : Error processing server $serverIP - $($_.Exception.Message)"
return $false
}
finally {
# Cleanup PSDrive
if (Get-PSDrive -Name $driveName -ErrorAction SilentlyContinue) {
Remove-PSDrive -Name $driveName -Force
Write-Verbose "Removed temporary PSDrive: $driveName"
}
}
}
# Copy to first web server
Write-Verbose "Starting copy to first web server ($webServer1)"
$result1 = Copy-CRLToServer -serverIP $webServer1 -sourcePath $sourcePath -crlName $crlName -credential $credential
# Copy to second web server
Write-Verbose "Starting copy to second web server ($webServer2)"
$result2 = Copy-CRLToServer -serverIP $webServer2 -sourcePath $sourcePath -crlName $crlName -credential $credential
# Final status report
if ($result1 -and $result2) {
Write-Verbose "CRL distribution completed successfully to both servers"
} else {
$failedServers = @()
if (-not $result1) { $failedServers += $webServer1 }
if (-not $result2) { $failedServers += $webServer2 }
Write-Verbose "Failed : CRL distribution failed for servers: $($failedServers -join ', ')"
exit 1
}
}
catch {
Write-Verbose "Failed : Unexpected error - $($_.Exception.Message)"
exit 1
}