Private/Export-EscCrlList.ps1

function Export-EscCrlList {
    <#
    .SYNOPSIS
        Gathers published CRLs (base + delta) into a folder, read-only.
    .DESCRIPTION
        Collects existing Certificate Revocation Lists without ever publishing a new
        one (it never runs 'certutil -crl', which would change CA state). Two sources:

          1. Local CertEnroll folder (%SystemRoot%\System32\CertSrv\CertEnroll\*.crl)
             when running on the CA host.
          2. AD-published CRLs read over LDAP from the CDP objects under
             CN=CDP,CN=Public Key Services,CN=Services,<configNC> - the
             certificateRevocationList / deltaRevocationList attributes. This works
             from any domain-joined host (serverless bind).

        Files are written as <cn>.crl (base) and <cn>+.crl (delta). Never throws.
    .PARAMETER CrlDir
        Destination folder (created if missing).
    .PARAMETER IsLocal
        When $true, also copy the local CertEnroll *.crl files.
    .PARAMETER Server
        Optional DC to bind for the AD read (default: serverless / current domain).
    .PARAMETER CaName
        Optional CA sanitized name to restrict the AD CDP objects to that CA.
    .OUTPUTS
        [pscustomobject] with Count and Detail.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string] $CrlDir,

        [Parameter(Mandatory = $false)]
        [bool] $IsLocal = $true,

        [Parameter(Mandatory = $false)]
        [string] $Server,

        [Parameter(Mandatory = $false)]
        [string] $CaName
    )

    if (-not (Test-Path -LiteralPath $CrlDir)) { New-Item -ItemType Directory -Path $CrlDir -Force | Out-Null }
    $count = 0
    $notes = @()

    if ($IsLocal) {
        try {
            $certEnroll = Join-Path $env:SystemRoot 'System32\CertSrv\CertEnroll'
            if (Test-Path -LiteralPath $certEnroll) {
                $localCrls = @(Get-ChildItem -LiteralPath $certEnroll -Filter '*.crl' -File -ErrorAction SilentlyContinue)
                foreach ($file in $localCrls) {
                    Copy-Item -LiteralPath $file.FullName -Destination (Join-Path $CrlDir $file.Name) -Force -ErrorAction SilentlyContinue
                    $count++
                }
                if ($localCrls.Count -gt 0) { $notes += ('CertEnroll: {0} file(s).' -f $localCrls.Count) }
            }
        }
        catch {
            $notes += ('CertEnroll error: {0}' -f $_.Exception.Message)
        }
    }

    try {
        $configNc = Get-EscConfigNamingContext -Server $Server
        if (-not [string]::IsNullOrWhiteSpace($configNc)) {
            $cdpRoot = 'CN=CDP,CN=Public Key Services,CN=Services,{0}' -f $configNc
            $filter = '(objectClass=cRLDistributionPoint)'
            if (-not [string]::IsNullOrWhiteSpace($CaName)) {
                $esc = $CaName -replace '\\', '\5c' -replace '\(', '\28' -replace '\)', '\29' -replace '\*', '\2a'
                $filter = '(&(objectClass=cRLDistributionPoint)(cn={0}))' -f $esc
            }
            $res = @(Invoke-EscLdapSearch -SearchRoot $cdpRoot -Filter $filter -Server $Server `
                -PropertiesToLoad @('cn', 'certificateRevocationList', 'deltaRevocationList') -SearchScope 'Subtree')
            $adCount = 0
            foreach ($r in $res) {
                $bag = ConvertTo-EscPropertyBag -SearchResult $r
                $cn = 'crl'
                if ($bag.ContainsKey('cn') -and @($bag['cn']).Count -gt 0) { $cn = [string]$bag['cn'][0] }
                $safe = ($cn -replace '[\\/:*?"<>|]', '_')

                if ($bag.ContainsKey('certificaterevocationlist') -and @($bag['certificaterevocationlist']).Count -gt 0) {
                    $b = $bag['certificaterevocationlist'][0]
                    if ($b -is [byte[]]) {
                        [System.IO.File]::WriteAllBytes((Join-Path $CrlDir ($safe + '.crl')), [byte[]]$b)
                        $count++; $adCount++
                    }
                }
                if ($bag.ContainsKey('deltarevocationlist') -and @($bag['deltarevocationlist']).Count -gt 0) {
                    $d = $bag['deltarevocationlist'][0]
                    if ($d -is [byte[]]) {
                        [System.IO.File]::WriteAllBytes((Join-Path $CrlDir ($safe + '+.crl')), [byte[]]$d)
                        $count++; $adCount++
                    }
                }
            }
            if ($adCount -gt 0) { $notes += ('AD CDP: {0} CRL(s).' -f $adCount) }
        }
    }
    catch {
        $notes += ('AD CDP error: {0}' -f $_.Exception.Message)
    }

    if ($notes.Count -eq 0) { $notes += 'No CRLs found (CertEnroll empty and none published to AD).' }
    return [pscustomobject]@{ Count = $count; Detail = ($notes -join ' ') }
}