Powershell can't update IIS cert, but IIS Manager accepts the same cert

I had Lets Encrypt working on our old web server (running Windows Server 2019). We replaced the web server with a new computer Windows Server 2022 Standard. I'm using win-acme to generate the certificates, and using the same powershell script on both the old and the new servers.

The powershell script looks for the thumbprint of the old certificate, copies the new cert to a bunch of other servers that haven't changed, then updates IIS on those other servers to use the new certificate.

The certificate is being copied over no problem and if I manually choose it in IIS Manager it works. (Loading the site in a web browser shows the new cert, and it's valid.) But when I try to update it in powershell I'm getting "A specified logon session does not exist. It may already have been terminated." This also causes an error to show up in the Event Viewer under Windows Logs\System:

The TLS server credential's certificate does not have a private key information property attached to it. This most often occurs when a certificate is backed up incorrectly and then later restored. This message can also indicate a certificate enrollment failure. The SSPI client process is SYSTEM (PID: 4).

When the script is finished, the site that was using the old cert is set to "Not Selected" in it's SSL Cert field in IIS Manager.

I thought it might be because the connection to the other servers was missing something so I tried running the powershell script on the computer that runs win-acme. It gave the same problem.

Why does powershell, (running as administrator) fail to update using this code, when IIS manager accepts the same cert no problem?

$thumbprintOld = "11111111111222222222222222222222222222222"
$certImported = Get-ChildItem -Path cert:\LocalMachine\WebHosting | ?{ $_.Thumbprint -Eq "CA11111111111111111111111111111111111111" }
    
Import-Module WebAdministration
$bindings = Get-WebBinding
foreach($b in $bindings)
{
    if(($b.certificateHash -eq $thumbprintOld))
    {
        Write-Host ("found host " + $b.bindingInformation)
        #$b.RemoveSslCertificate()
        $b.AddSslCertificate($certImported.GetCertHashString(), "WebHosting")
    }
}

Note the commented line: On the old server we didn't need it, but I tried putting it in to see if it fixed it and it made no change so I commented it out.

The best way to copy a cert to multiple IIS servers is to use the Centralized Certificate Store feature. This involves copying the PFX to a share (either common or on your destination servers), then configure the CCS feature in IIS and set your IIS https bindings to use CCS.

From then on whenever you update the PFX on the share, IIS will pick it up automatically. This has the advantage that applicationhost.config also doesn't get a write and IIS doesn't have to reload it (which happens when updating a binding thumbprint, even though nothing changes in applicationhost.config), which can be beneficial for servers with many sites.

Regarding your script, how you are importing your cert (and what it's key type is) matters because it impacts the private key storage and permissions.

2 Likes