Private/Split-CertChain.ps1

function Split-CertChain {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,Position=0)]
        [string]$FullChainPath,
        [Parameter(Mandatory,Position=1)]
        [string]$OutputCert,
        [Parameter(Mandatory,Position=2)]
        [string]$OutputChain
    )

    # The finalized certificate we pull down from the server is supposed to be a
    # PEM chain that starts with the leaf cert followed by the rest of the chain.
    # We want to split the leaf from the rest of the chain and output two files.

    $CERT_BEGIN = '-----BEGIN CERTIFICATE-----*'
    $CERT_END   = '-----END CERTIFICATE-----*'

    # resolve relative paths
    $FullChainPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($FullChainPath)
    $OutputCert = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputCert)
    $OutputChain = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputChain)

    # Usually, PEM files are ANSI/ASCII encoded with UNIX line endings which means none of the
    # normal PowerShell stuff for outputting files will work. So we'll use a .NET StreamWriter
    # instead.
    try {
        $swCert = New-Object IO.StreamWriter($OutputCert, $false, [Text.Encoding]::ASCII)
        $swChain = New-Object IO.StreamWriter($OutputChain, $false, [Text.Encoding]::ASCII)
        $swCert.NewLine = "`n"
        $swChain.NewLine = "`n"

        $startCert = $false; $endCert = $false
        $startChain = $false
        foreach ($line in (Get-Content $FullChainPath)) {

            # skip whitespace
            if ([string]::IsNullOrWhiteSpace($line)) { continue }

            # find the first line of the cert
            if (!$startCert) {
                if ($line -like $CERT_BEGIN) {
                    Write-Debug "found first cert start"
                    $startCert = $true
                    $swCert.WriteLine($line)
                }
                continue
            }

            # write the rest of the lines of the cert and watch for the end
            if ($startCert -and !$endCert) {
                $swCert.WriteLine($line)
                if ($line -like $CERT_END) {
                    Write-Debug "found first cert end"
                    $endCert = $true
                }
                continue
            }

            # now we're looking for chain certs
            if (!$startChain) {
                if ($line -like $CERT_BEGIN) {
                    Write-Debug "found chain cert start"
                    $startChain = $true
                    $swChain.WriteLine($line)
                }
                continue
            } else {
                $swChain.WriteLine($line)
                if ($line -like $CERT_END) {
                    Write-Debug "found chain cert end"
                    $startChain = $false
                }
                continue
            }

        }

    } finally {
        if ($swCert -ne $null) { $swCert.Close() }
        if ($swChain -ne $null) { $swChain.Close() }
    }

}