Public/Set-NSPIisBindingCertificate.ps1

function Set-NSPIisBindingCertificate {
    <#
    .SYNOPSIS
        Points IIS https bindings at a certificate in LocalMachine\My (or another LocalMachine store).
    .DESCRIPTION
        Takes bindings by SiteName and BindingInformation, typically piped from Get-NSPIisBinding.
        The certificate must be in the store with its private key. IIS writes the change to http.sys
        as it does from IIS Manager; the site keeps running.

        One row per binding: SiteName, BindingInformation, PreviousThumbprint, Thumbprint, and Action
        (Updated, AlreadySet, WhatIf).
    .PARAMETER SiteName
        The site.
    .PARAMETER BindingInformation
        The binding, as ip:port:host (for example *:443:www.contoso.com).
    .PARAMETER Thumbprint
        The certificate to use.
    .PARAMETER StoreName
        The LocalMachine store holding it: My (default) or WebHosting.
    .EXAMPLE
        Set-NSPIisBindingCertificate -SiteName 'Default Web Site' -BindingInformation '*:443:' -Thumbprint 0123456789ABCDEF0123456789ABCDEF01234567
    .EXAMPLE
        Get-NSPIisBinding -Certificate $new | Where-Object Match | Set-NSPIisBindingCertificate -Thumbprint $new.Thumbprint
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([pscustomobject])]
    param(
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)][string]$SiteName,
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)][string]$BindingInformation,
        [Parameter(Mandatory)][ValidatePattern('^[0-9A-Fa-f]{40}$')][string]$Thumbprint,
        [ValidateSet('My', 'WebHosting')][string]$StoreName = 'My'
    )

    begin {
        $Thumbprint = $Thumbprint.ToUpperInvariant()
        $store = New-Object System.Security.Cryptography.X509Certificates.X509Store $StoreName, 'LocalMachine'
        try {
            $store.Open('ReadOnly')
            $certificate = @($store.Certificates.Find('FindByThumbprint', $Thumbprint, $false))[0]
        } finally {
            $store.Close()
        }
        if (-not $certificate) { throw "Certificate $Thumbprint isn't in LocalMachine\$StoreName." }
        if (-not $certificate.HasPrivateKey) { throw "Certificate $Thumbprint in LocalMachine\$StoreName has no private key." }
        $hash = [byte[]]::new(20)
        for ($i = 0; $i -lt 20; $i++) { $hash[$i] = [Convert]::ToByte($Thumbprint.Substring($i * 2, 2), 16) }
    }

    process {
        $manager = Get-NSPIisServerManager
        try {
            $site = $manager.Sites[$SiteName]
            if (-not $site) { throw "IIS has no site named '$SiteName'." }
            $binding = $site.Bindings | Where-Object { $_.Protocol -eq 'https' -and $_.BindingInformation -eq $BindingInformation } | Select-Object -First 1
            if (-not $binding) { throw "Site '$SiteName' has no https binding $BindingInformation." }
            $previous = if ($binding.CertificateHash) { ([BitConverter]::ToString([byte[]]$binding.CertificateHash) -replace '-', '').ToUpperInvariant() } else { '' }
            $row = [pscustomobject]@{
                SiteName           = $SiteName
                BindingInformation = $BindingInformation
                PreviousThumbprint = $previous
                Thumbprint         = $Thumbprint
                Action             = ''
            }
            if ($previous -eq $Thumbprint -and $binding.CertificateStoreName -eq $StoreName) {
                $row.Action = 'AlreadySet'
            } elseif ($PSCmdlet.ShouldProcess("$SiteName $BindingInformation", "Use certificate $Thumbprint ($($certificate.Subject))")) {
                $binding.CertificateHash = $hash
                $binding.CertificateStoreName = $StoreName
                $manager.CommitChanges()
                $row.Action = 'Updated'
            } else {
                $row.Action = 'WhatIf'
            }
            $row
        } finally {
            $manager.Dispose()
        }
    }
}