Private/ConvertTo-NSPIisBindingRow.ps1

function ConvertTo-NSPIisBindingRow {
    # One binding as a row, from plain values so it can be tested without IIS. With Certificate,
    # Match says whether that certificate should replace the binding's current one, and MatchReason
    # why (or why not):
    # a host name binding (SNI, or a host header on a shared IP) matches when the host name is on
    # the certificate; a binding without a host name matches when its current certificate covers
    # one of the same names - the renewal case.
    [CmdletBinding()]
    [OutputType([pscustomobject])]
    param(
        [Parameter(Mandatory)][string]$SiteName,
        [long]$SiteId,
        [string]$SiteState,
        [Parameter(Mandatory)][string]$Protocol,
        [Parameter(Mandatory)][AllowEmptyString()][string]$BindingInformation,
        [AllowNull()][byte[]]$CertificateHash,
        [AllowEmptyString()][string]$CertificateStoreName,
        [int]$SslFlags,
        [AllowNull()][System.Security.Cryptography.X509Certificates.X509Certificate2]$CurrentCertificate,
        [AllowNull()][System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate
    )

    # ip:port:host - the IP may be an IPv6 literal in brackets, so split from the right.
    $ipAddress = ''; $port = 0; $hostName = ''
    if ($BindingInformation -match '^(?<ip>.*):(?<port>\d+):(?<host>[^:]*)$') {
        $ipAddress = $Matches.ip; $port = [int]$Matches.port; $hostName = $Matches.host
    }
    $thumbprint = if ($CertificateHash -and $CertificateHash.Length) { ([BitConverter]::ToString($CertificateHash) -replace '-', '').ToUpperInvariant() } else { '' }
    $currentNames = @(if ($CurrentCertificate) { Get-NSPIisDnsName -Certificate $CurrentCertificate })

    $row = [pscustomobject]@{
        SiteName            = $SiteName
        SiteId              = $SiteId
        SiteState           = $SiteState
        Protocol            = $Protocol
        BindingInformation  = $BindingInformation
        IPAddress           = $ipAddress
        Port                = $port
        HostName            = $hostName
        Sni                 = [bool]($SslFlags -band 1)
        CentralCertStore    = [bool]($SslFlags -band 2)
        Thumbprint          = $thumbprint
        StoreName           = $CertificateStoreName
        CertificateFound    = [bool]$CurrentCertificate
        CertificateSubject  = $(if ($CurrentCertificate) { $CurrentCertificate.Subject } else { '' })
        CertificateNotAfter = $(if ($CurrentCertificate) { $CurrentCertificate.NotAfter } else { $null })
        CertificateNames    = $currentNames
        Match               = $null
        MatchReason         = ''
    }
    if (-not $Certificate) { return $row }

    $names = @(Get-NSPIisDnsName -Certificate $Certificate)
    $match = $false
    $reason = if ($Protocol -ne 'https') {
        'Not an https binding'
    } elseif ($row.CentralCertStore) {
        'Uses the Central Certificate Store'
    } elseif ($thumbprint -eq $Certificate.Thumbprint.ToUpperInvariant()) {
        'Already uses this certificate'
    } elseif ($hostName) {
        if (Test-NSPIisHostMatch -HostName $hostName -Name $names) { $match = $true; "Host name $hostName is on the certificate" }
        else { "Host name $hostName is not on the certificate" }
    } elseif (-not $thumbprint) {
        'No certificate bound'
    } elseif (-not $CurrentCertificate) {
        'Current certificate is not in the store'
    } elseif (@($currentNames | Where-Object { $_ -in $names }).Count) {
        $match = $true
        'Current certificate covers the same names'
    } else {
        'Current certificate is for other names'
    }
    $row.Match = $match
    $row.MatchReason = $reason
    $row
}