Can I change a cert thumbprint in IIS:SSLBindings using powershell?

I am a big powershell novice and this is my first post, so I'll apologize in advance for the lack of knowledge and/or incorrect use of terms... I've spent hours searching for and trying out various code snippets to create a script that can be used to replace hundreds of SSL certificates on our IIS (7.5 & up) web servers. What I've discovered so far is that the SSL bindings are apparently stored in [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters\SslBindingInfo]. The following powershell script allows me to retrieve all the IIS SSL bindings that exist on a server and a simple comparison of CNames allows me to find the specific binding(s) matching the cert we're updating. I've also found that I can manually overtype the SslCertHash value in the registry keys beneath the location above with a different thumbprint and it changes the cert binding in IIS. So it seems like there should be a very simple way in powershell to just replace the current thumbprint with the new thumbprint in the applicable binding without having to retrieve IP address, port, and/or siteID (the running script already has me at the binding instance that I need to change). I know there are some roundabout ways of changing the binding, but my limited exposure to powershell would suggest that a more direct command should exist to accomplish that. Is that just wishful thinking???

My script so far:

    Import-Module -Name WebAdministration

    $SearchCName = '*myhost.domain.com*'
    $NewCertThumbprint = '1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R9S0T'

    Get-ChildItem -Path IIS:SSLBindings | ForEach-Object -Process {
        if ($_.Sites)
        {
            $certificate = Get-ChildItem -Path CERT:LocalMachine/My |
                Where-Object -Property Thumbprint -EQ -Value $_.Thumbprint

            [PsCustomObject]@{
                Sites                        = $_.Sites.Value
                CertificateDnsNameList       = $certificate.DnsNameList
                CertificateNotAfter          = $certificate.NotAfter
                CertificateThumbprint        = $certificate.Thumbprint
                CertificateSubject           = $certificate.Subject
                CertificateIssuer            = $certificate.Issuer
                CertificateTPfromSSLBinding  = $_.Thumbprint
                CertificateBindingIPAddr     = $_.IPAddress
                CertificatePort              = $_.Port
                }

                if ($certificate.Subject -like $SearchCName)
                    { Write-Output 'True' } 
                Else 
                    { Write-Output 'False' }
        }
    } 

    Sample output:

    Sites                       : testsite1
    CertificateDnsNameList      : {}
    CertificateNotAfter         : 2/16/2021 1:41:55 PM
    CertificateThumbprint       : 6DA6A25F5C756D710D033D1146A3097EE0E9F430
    CertificateSubject          : CN=testsite1.domain.com, OU=IT Security, O=My
                          Company, L=MyCity, S=MyState, C=US
    CertificateIssuer           : CN=My Company Internal CA, OU=PKI, O=My Company, 
                          C=US
    CertificateTPfromSSLBinding : 6DA6A25F5C756D710D033D1146A3097EE0E9F430
    CertificateBindingIPAddr    : 10.39.205.19
    CertificatePort             : 443
    False

    Sites                       : testsite2
    CertificateDnsNameList      : {}
    CertificateNotAfter         : 1/2/2022 4:39:12 PM
    CertificateThumbprint       : 6D2DC913256CCADBD3983773CAC20440D918F091
    CertificateSubject          : CN=testsite2.domain.com, OU=IT Security, O=My 
                          Company, L=MyCity, S=MyState, C=US
    CertificateIssuer           : CN=My Company Internal CA, OU=PKI, O=My Company, 
                          C=US
    CertificateTPfromSSLBinding : 6D2DC913256CCADBD3983773CAC20440D918F091
    CertificateBindingIPAddr    : 10.39.205.24
    CertificatePort             : 443
    False

My Powershell version: Major Minor Build Revision


5 0 10586 117

Thanks, Randy

1 answer

  • answered 2018-10-11 03:13 postanote

    Honestly, this could be a duplicate of this stackoverflow discussion and the provided answers.

    Powershell update IIS Bindings

    It's OK to be new to something, but it's vital you get some training before you begin to alleviate any unnecessary frustration / confusion where possible.

    There is tons of no cost video, audio and eBook resources all over the web for it. When it comes to IIS stuff, your key resource is the MS IIS Team site.

    https://www.iis.net

    Yet, there are lots of resources that are readily available as well.

    Just as you discovered the way to get the SSL site / binding info, that same effort should be used to complete your task. This sort of this is not only directly available on the Microsoft docs site, but all over the web.

    As for you immediate need, the MS document details below, should handle your use case.

    PowerShell Snap-in: Configuring SSL with the IIS PowerShell Snap-in

    by IIS Team

    To enable SSL three steps are involved:

    1. Acquiring and installing a certificate
    2. Creating an SSL binding in IIS
    3. Assigning the certificate to the IP:Port of the IIS binding

    and optionally:

    • Enforcing SSL on your web-site

    You can look at the certificates in the certificate store using the certificate provider:

    dir cert:\localmachine\my
    
        Directory: Microsoft.PowerShell.Security\Certificate::localmachine\my
    
    Thumbprint                                Subject
    ----------                                -------
    7ABF581E134280162AFFFC81E62011787B3B19B5  CN=MyTestServer
    

    Creating an SSL Binding

    We are adding the SSL binding to the Default Web Site using one of the task-based cmdlets called New-WebBinding:

    New-WebBinding -Name "Default Web Site" -IP "*" -Port 443 -Protocol https
    
    cd SslBindings
    dir
    
    get-item cert:\LocalMachine\MY\7ABF581E134280162AFFFC81E62011787B3B19B5 | new-item 0.0.0.0!443
    

    Now you can use the certificate hash we got in step one and associate it with all IP addresses (0.0.0.0) and the SSL port 443:

    Or you can use the following directions:

    Use Powershell to bind SSL Certificates to an IIS Host Header Site

    $hostname="test.west-wind.com"
    $iisSite="Default Web Site"
    dir certs:\localmachine\my
    $cert = (Get-ChildItem cert:\LocalMachine\My 
          | where-object { $_.Subject -like "*$hostname*" } 
          | Select-Object -First 1).Thumbprint
    
    # If you have an existing certificate you can import it with CertUtil:
    
    # From a PFX:
    certutil -importpfx <pfx_file>
    
    
    # From a CER:
    certutil –addstore MY <Cer_File>
    
    dir certs:\localmachine\my
    $cert = "<thumbprintOfYourCert>"
    
    # To bind hostname and IP to your certificate you can now do:
    $guid = [guid]::NewGuid().ToString("B")
    netsh http add sslcert hostnameport="${hostname}:443" certhash=$cert certstorename=MY appid="$guid"
    
    Bind the Web Site to the Host Header IP
    
    Finally we need to also bind Web site to the IP/Hostheader/Port combination.
    New-WebBinding -name $iisSite -Protocol https  -HostHeader $hostname -Port 443 -SslFlags 1
    
    
    # Notice the -SslFlag=1 setting, which enables SNI on this binding.
    
    # If for whatever reason you need to remove the binding you can use:
    netsh http delete sslcert hostnameport=test.west-wind.com:443
    

    After understanding all the above, you could just use a one-liner to do this in one call:

    Get-ChildItem -Path cert:\LocalMachine\MY | Where {$_.Subject -match "CN=[*.mycrt.mydomain.com]*"}  | Select -First 1 | ni 0.0.0.0!443
    

    See also:

    Weekend Scripter: Use PowerShell to Update SSL Bindings