Let's get one thing straight. I hate cryptography and certificates. Over my career, I've been the "certificate guy" on a few occasions. However, it was just another hat for a system administrator. I never got to the point to where I completely understood the technology and it seemed like every task I tried to accomplish around that area seemed to never work out. It's definitely an unforgiving technology for sure.

Let me tell you a story about automating getting a certificate installed on an IIS server with PowerShell.

The Mission

From a client, request a new public Digicert certificate, get it installed on a remote Windows Server 2012 R2 Core Server running IIS 8.5 in a workgroup, set a SSL binding to a website and use the installed certificate for the binding. Simple, right? LOLz!

How it's Done, Son! .Summary

In a nutshell, it takes X steps to make this happen.

  1. Generate a certificate signing request on the computer where the cert will be installed. In my case, I only had WinRM access so I had to execute certreq.exe on the remote server using Invoke-Command and send the content of the CSR to a local file.
  2. Get the CSR signed by a public CA. (No help here -a pretty cert just came back from security that I worked with). In my case, the security team gave me back a P7B collection of certs rolled up into a .CER file which included the cert I was looking for as well as the intermediate certs. This took a bit of tinkering to work.
  3. Complete the certificate signing request on the computer where the cert will be installed. This will get the certificate into the certificate store.
  4. Create a SSL IIS web binding on the server.
  5. Attach the certificate to the web binding.

How it's Done, Son! .For Real

Generating the CSR

Your first task will be to run certreq.exe on the remote server to gather up a request file. �To do this, certreq.exe requires an INF file as input. This file is used for all the various options your certificate will end up having. Without going into a ton of detail, this is a copy of the INF file that I was using.

[Version]
Signature = "$Windows NT$"
[NewRequest]
Subject = "C=US,S=State,L=City,O=Company,OU=IT,CN=Name"
Exportable = TRUE
KeyLength = 2048
KeySpec = 1
KeyUsage = 0xa0
MachineKeySet = True
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
Silent = True
SMIME = False
RequestType = PKCS10

You'll see in the New-CertificateSigningRequest function that I make it super-easy for you to customize this. Actually, if you use my functions you'll never even see this file as it's only needed temporarily to create the CSR (request file).

Next, you'll need to get this INF file on the remote server and run certreq.exe with the following parameters like certreq.exe -new "$InfFilePath" "$reqFilePath".

This will generate a CSR (request file) on the remote computer. You'll then need to send this file to your security team. This will also create a certificate containing both the private key and the public key in the Certificate Issued Requests in the local machine context.

n1gSF

Completing the CSR

In my case, I got back a single CER file. �I created a function to simply import this directly into the Personal store in the local machine context to find that IIS couldn't see it. The reason was because the certificate had to contain the private key as well. �Simply importing the certificate into the Personal store would not work. �I had to complete the certificate request use certreq.exe.

To do this, you will need to copy the certificate you receive from your security team onto the remote server and then execute certreq.exe like this certreq.exe -accept -machine "C:\issuedcert.cer".

You'll always need to ensure that the response certificate always goes into the local machine context by using the -machine parameter. This should complete successfully according to everything I read but it definitely did not for me. �For some reason, I was receiving an error that looked like this:

3hIa8
Error requesting certificate

It turns out this means that the public key in the request file did not match what was returned by the security team. �To test this, simply run certutil.exe -dump requestfile.req and certutil -dumpissuedcert.cer. Scroll down through the output until you see the public key area.

2015-10-15_17-02-32

Copy out each of these private keys and compare in a text editor to ensure they're the same. If not, get onto your security team for not signing your request right!

If those match, you're good and you should not receive that error.

Create the SSL Binding

On the remote server run:

Import-Module WebAdministration
New-WebBinding -Name $WebsiteName -IP * -Port 443 -Protocol https

Attach the Certificate to the SSL Binding

On the remote server, run:

$certificate = Get-Item Certificate:\localmachine\My\$Thumbprint
$certificate | New-Item "IIS:\SSLBindings\0.0.0.0!443"

Get the PowerShell Goodies

If all goes well, you should be done! �Now, if you need a little help doing this I've created three functions to make it happen a lot easier. �Head on over to my Github repo to get the functions:

https://github.com/adbertram/Random-PowerShell-Work/tree/master/Certificates
https://github.com/adbertram/Random-PowerShell-Work/tree/master/IIS

Example code

## Send the file that this outputs to your certificate people 
New-CertificateSigningRequest -SubjectHost 'somesubject' -FilePath 'C:\somefile.req' -ComputerName REMOTESERVER

## Import the cert receieved
Import-CertificateSigningRequestResponse -FilePath C:\issuedcert.cer -ComputerName REMOTESERVER

##Create the binding and attach the cert.
New-IISWebBinding -ComputerName 'zapp09rpr01' -WebsiteName GHI -Protocol https -Port 443 -Certificate $cert

Join the Jar Tippers on Patreon

It takes a lot of time to write detailed blog posts like this one. In a single-income family, this blog is one way I depend on to keep the lights on. I'd be eternally grateful if you could become a Patreon patron today!

Become a Patron!