Powershell : Distributing the CRL to Web Servers (running Windows)


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

  1. The Offline Root Certificate server is running Windows
  2. The Offline Root Certificate server is in a workgroup
  3. You have Windows servers running IIS for hosting the CRL and other PKI files
  4. Your IIS hosted servers are in the domain and have a certain directory structure
  5. You have access to the Offline Root Certificate server (after it has been powered up)
  6. 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:

  1. Runs the command "certutil -crl" this will generate a new CRL file with a valid validity period
  2. Runs the command "certutil" to extract the name of the CA from the Name attribute stored as $crlName
  3. Obtain the generate folder from the folder C:\Windows\System32\certsrv\CertEnroll\$crlName.crl
  4. 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
  5. 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
}

Previous Post Next Post

نموذج الاتصال