The following PowerShell snippet can be used to quickly install an SSL (or TLS) certificate in Windows Server. It assumes you have a PFX file and its password. The default location is Cert:\LocalMachine\My
, to use for IIS websites.
In this script you have to adjust a few bits for every certificate you install, so use it as a base or starting point for your own scripting. After importing the certificate, it also changes the .FriendlyName
visible in MMC and IIS Manager, doing so you always know exactly which certificate you need to select. Neat, right? >:-)
#
# Install SSL certificate in Windows with PowerShell
#
$certificatename = "CHANGEME.pfx"
$mypwd = Get-Credential -UserName "${certificatename} SSL cert" -Message 'Enter password below'
$params = @{
FilePath = \\TSCLIENT\C\Users\Jan\SSL\${certificatename}
CertStoreLocation = 'Cert:\LocalMachine\My'
Password = $mypwd.Password
}
$cert = Import-PfxCertificate @params
[string]$thumbprint = $cert.Thumbprint
(Get-ChildItem -Path Cert:\LocalMachine\My\${thumbprint}).FriendlyName = "${certificatename} 2024"
A couple of things happen here:
- First, I define a variable for my certificate name,
- And secondly I use
Get-Credential
to store the certificate password into a variable. This way, the SSL/TLS certificate password is not stored in your PowerShell history file. - Thirdly, we define the certificate parameters. And as you can see by the FilePath value, I use a remote desktop
\\TSCLIENT
share to point to my local computer. Doing so allows me to have certificates stored at one location on my computer (because you know, clients always sent them by email), and use the RDP share to transfer the certificate to the server. At last we define the Certificate Store location (as displayed:Cert:\LocalMachine\My
) and the password. - Last, but not least: all this is fed to
Import-PfxCertificate
, which in its turn saves the object into$cert
and this allows us to change its.FriendlyName
property.
You can find more information about Import-PfxCertificate on Microsoft Learn and the code shown above is also available as a Gist: https://gist.github.com/Digiover/a2db4125efb069d62a8fedcd23212103.
Psst, did you know you can use certutil -v -dump certificate_name.pfx
to look up and verify an SSL certificate’s Common Name (Subject) and Subject Alternative Name (SAN)? Or in PowerShell, you can use:
Get-PfxCertificate certificate_name.pfx | Select-Object Subject,DnsNameList
Bind SSL certificate to website in IIS using netsh
Once your new certificate is installed, you bind the SSL certificate to the website requiring it. In my workflow I compare the thumbprint of current installed certificate with the output I get from netsh.exe http show sslcert
. If it matches, I have a certificate that needs updating. This means you must have an administration of thumbprints. Adjust the code to your environment.
The first step is to retrieve a list of all installed certificates in your certificate store with some properties we find interesting. For this step use the following code:
$TxtBindings = (& C:\Windows\System32\netsh.exe http show sslcert) | select-object -skip 3 | out-string
$nl = [System.Environment]::NewLine
$Txtbindings = $TxtBindings -split "$nl$nl"
$BindingsList = foreach ($Binding in $Txtbindings) {
if ($Binding -ne "") {
$Binding = $Binding -replace " ", "" -split ": "
[pscustomobject]@{
IPPort = ($Binding[1] -split "`n")[0]
CertificateHash = ($Binding[2] -split "`n" -replace '[^a-zA-Z0-9]', '')[0]
AppID = ($Binding[3] -split "`n")[0]
CertStore = ($Binding[4] -split "`n")[0]
}
}
}
This code comes partly from Kelvin Tegelaar’s blogpost Monitoring with PowerShell: Monitor SSL certificates.
Once you have $BindingsList
, it’s time to parse it line by line and compare the .CertificateHash
property with your currently installed certificate thumbprint (hash, $TlsCertOldThumbprint
in the code below). A match means the certificate needs updating. First remove the old certificate HTTP binding and secondly, add a new HTTP binding with the new certificate. All using netsh http
.
$TlsCertOldThumbprint = ""
foreach($line in $BindingsList) {
if($line.CertificateHash -eq "$TlsCertOldThumbprint") {
$HostnamePort = $(${line}.IPPort).Trim()
&C:\Windows\System32\netsh.exe http delete sslcert hostnameport=$HostnamePort
if($LASTEXITCODE -ne 0) {
Write-Host "[!!] Error removing certificate"
} else {
# any valid GUID will do, generate one with:
# [guid]::NewGuid().ToString("B")
$appid = '{6ccd10b0-adff-4c3a-83cd-e4e5fb78ba2a}'
&C:\Windows\System32\netsh.exe http add sslcert hostnameport=$HostnamePort certhash=$TlsCertNewThumbprint appid=$appid certstorename=My
if($LASTEXITCODE -ne 0) {
Write-Host "[!!] Error adding certificate"
} else {
Write-Host "New TLS certificate successfully installed on $HostnamePort"
}
}
}
}