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
- $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
- $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
- Write-Host "base64Cert: " ([System.Convert]::ToBase64String($cert.GetRawCertData()))
- Write-Host "base64CertHash:" ([System.Convert]::ToBase64String($cert.GetCertHash()))
- 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
- $cert = Get-ChildItem -Path cert:\CurrentUser\My | ?{$_.Subject -eq "CN=TodoListDaemonWithCert"}
Need to exporting the public key? Straightforward.
Export Public Key
- Export-Certificate -Type CERT -Cert $cert -FilePath "c:\temp\sample.cer"
What about the private key?
Export Private Key
- $cred = Get-Credential
- Export-PfxCertificate -Cert $cert -Password $cred.Password -FilePath "c:\temp\sample.pfx"
How about removing a certificate? Also very simple.
Removing Certificates
- 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.