'Issue when setting IIS binding certificate in Powershell

I'm writing a Powershell script to go through my list of IIS bindings, find any that have a particular 'old' cert thumbprint, and replace their certs with a cert that has a 'new' thumbprint. This is so I can update the certificate for many bindings, because we use the same certificate for a lot of sites so we need to update all bindings that have the old cert to the new cert. Here's what I've come up with:

##### EDIT THESE VARIABLES #####
$SiteName = "movc-website-www"
$OldCertThumbprint = "‎76 ae 0b 2e b9 f7 45 ce 27 c4 02 6e 90 66 62 93 69 d7 5e 4c"
$ReplacementCertThumbprint = "‎7f fa 9f f3 90 b8 a2 d8 4c 98 51 47 a5 64 1d 90 f6 2f ca 73"

##### FUNCTIONS #####
Function ReplaceWebsiteBinding {
    Param(
        [string] $SiteName,
        [string] $OldCertThumbprint,
        [string] $ReplacementCertThumbprint
    );

    Import-Module WebAdministration;

    $ReplacedCount = 0

    $IISBindings = (Get-ItemProperty -Path "IIS:\Sites\$SiteName" -Name Bindings)
    for ($i=0; $i -lt ($IISBindings.Collection).Length; $i++) {
        if (($IISBindings.Collection[$i]).certificateHash -eq $OldCertThumbprint) {
            ($IISBindings.Collection[$i]).RebindSslCertificate($ReplacementCertThumbprint, "My")
            $ReplacedCount++
        }
    }

    Return $ReplacedCount
}

##### MAIN PROGRAM #####
$OldCertThumbprint = $OldCertThumbprint.Replace(" ", "").ToUpper()
$ReplacementCertThumbprint = $ReplacementCertThumbprint.Replace(" ", "").ToUpper()

# Check that cert with given thumbprints exist
$FoundCert = Get-ChildItem -Path Cert:\LocalMachine\My |
    Where-Object { $_.Thumbprint -eq $OldCertThumbprint } |
    Select-Object -ExpandProperty Thumbprint
if (!$FoundCert) {
    Write-Host "Old cert with thumbprint $OldCertThumbprint not found!"
    Exit
}

$FoundCert = Get-ChildItem -Path Cert:\LocalMachine\My |
    Where-Object { $_.Thumbprint -eq $ReplacementCertThumbprint } |
    Select-Object -ExpandProperty Thumbprint

if (!$FoundCert) {
    Write-Host "Replacement cert with thumbprint $ReplacementCertThumbprint not found!"
    Exit
}

# Associate new cert with bindings that have old cert
$ReplacedCount = ReplaceWebsiteBinding $SiteName $OldCertThumbprint $ReplacementCertThumbprint

Write-Host "Replaced $ReplacedCount binding(s)."

The trouble is this doesn't work because the line calling .RebindSslCertificate(...) gives me the following Powershell error:

Value does not fall within the expected range.
At (...)
+             ($IISBindings.Collection[$i]).RebindSslCertificate($Repla ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], ArgumentException
    + FullyQualifiedErrorId : System.ArgumentException

Not the most useful error really, and I can't figure out why I'm getting it. The arguments look OK to me; the thumbprint was found by the Get-ChildItem code and "My" looks fine. The only thing I can think of is that it might be looking in the current user certificate store rather than the local machine certificate store, which is where the desired certs are. Can anyone help me with why this error is happening?



Solution 1:[1]

It turns out I was having the same problem as described here (RebindSslCertificate the certificate is just the same as removing it and then calling AddSslCertificate). When copying the thumbprint from the certificate dialog in Windows for some stupid reason it inserts a zero-width LTR character at the beginning of the string so my thumbprint was invalid. I added a check for this at the beginning of my script to prevent it:

if ($OldCertThumbprint -match "[\W-[\ ]]") {
    Write-Host "Old cert thumbprint contains non-word characters, maybe a zero-width LTR Unicode character at the beginning.  You almost certainly don't want this!  Aborting!"
    Exit
}
if ($ReplacementCertThumbprint -match "[\W-[\ ]]") {
    Write-Host "Replacement cert thumbprint contains non-word characters, maybe a zero-width LTR Unicode character at the beginning.  You almost certainly don't want this!  Aborting!"
    Exit
}

Solution 2:[2]

I found a great script to "find any [bindings] that have a particular 'old' cert thumbprint, and replace their certs with a cert that has a 'new' thumbprint" here (archived here)

Given the new cert is already installed.

The minimal version is:

$OldThumbprint = "########################################"
$NewThumbprint = "########################################"

Get-WebBinding | Where-Object { $_.certificateHash -eq $OldThumbprint} | ForEach-Object {
    Write-Host "Replacing Cert For "  $_ 
    $_.RemoveSslCertificate()
    $_.AddSslCertificate($NewThumbprint, 'My')
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jez
Solution 2 Myster