Kirk Evans Blog

.NET From a Markup Perspective

Using PowerShell With Certificates

This post will demonstrate using PowerShell cmdlets to create, read, and delete certificates.  Spoiler alert: it’s dead simple.

Background

I was working through the example Authenticating to Azure AD in daemon apps with certificates and I saw this:

makecert -r -pe -n "CN=TodoListDaemonWithCert" -ss My -len 2048 TodoListDaemonWithCert.cer -sv TodoListDaemonPrivateKey.pvk

Easy to read, right?  I mean, anyone can read that and understand it will create a self-signed certificate where the private key is exportable and store it in the current user’s personal certificate store, right?

Inevitably, when I tell someone to “just use a self-signed certificate”, I inevitably get a question asking something like “Makecert.exe is not on my computer, where do I get it from?”  You need to download the Windows SDK in order to obtain it, but that’s a pretty large tax for what seems like a simple function, creating a self-signed certificate.  The sample then goes on with some more code to read a .CER file using PowerShell, using the .NET X509Certificate2 class:

$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cer.Import("TodoListDaemonWithCert.cer")
$bin = $cer.GetRawCertData()
$base64Value = [System.Convert]::ToBase64String($bin)
$bin = $cer.GetCertHash()
$base64Thumbprint = [System.Convert]::ToBase64String($bin)
$keyid = [System.Guid]::NewGuid().ToString()

It struck me that this is fairly complicated for something that should have just been 1 line of code.

Working With Certificates in PowerShell

If you Google with Bing you’ll see a whole bunch of blog posts that show fairly long-winded examples of creating self-signed certificates using the .NET X509Certificate2 class.  Turns out it’s so much simpler than that.  The equivalent of the above command is:

New-SelfSignedCertificate
  1. $cert = New-SelfSignedCertificate -Subject "CN=TodoListDaemonWithCert" -CertStoreLocation cert:\CurrentUser\My -Provider "Microsoft Strong Cryptographic Provider"


That’s it.  No need to install the Windows SDK. 

The cmdlet returns the certificate object (which is actually a System.Security.Cryptography.X509Certificates.X509Certificate2 .NET type).  So you can just use a variable to store it:

New-SelfSignedCertificate
  1. $cert = New-SelfSignedCertificate -Subject "CN=TodoListDaemonWithCert" -CertStoreLocation cert:\CurrentUser\My -Provider "Microsoft Strong Cryptographic Provider"

Since you have an X509Certificate2 object, you can easily interrogate its properties:

Certificate Properties
  1. Write-Host "base64Cert: " ([System.Convert]::ToBase64String($cert.GetRawCertData()))
  2. Write-Host "base64CertHash:" ([System.Convert]::ToBase64String($cert.GetCertHash()))
  3. Write-Host "keyID:" ([System.Guid]::NewGuid().ToString())


Need to get an existing certificate by a property such as its Subject?  You can use the Get-ChildItem cmdlet and specify the path to the certificate store.

Get-ChildItem
  1. $cert = Get-ChildItem -Path cert:\CurrentUser\My | ?{$_.Subject -eq "CN=TodoListDaemonWithCert"}


Need to exporting the public key?  Straightforward.

Export Public Key
  1. Export-Certificate -Type CERT -Cert $cert -FilePath "c:\temp\sample.cer"


What about the private key?

Export Private Key
  1. $cred = Get-Credential
  2. Export-PfxCertificate -Cert $cert -Password $cred.Password -FilePath "c:\temp\sample.pfx"

How about removing a certificate?  Also very simple.

Removing Certificates
  1. Remove-Item -Path ("cert:\CurrentUser\My\" + $cert.Thumbprint)


Summary

I’m guilty, I have been doing this a long time and stuck in my ways.  I default to makecert.exe because that’s what I know, but it’s useful to have tools that are far easier to read and understand.