Windows PowerShell met CAPICOM

Part of what I do at Microsoft is build demos. The latest demo our team is working on, DinnerNow.NET, makes use of several certificates for cardspace, which need to be installed in the certificate store. Furthermore the NETWORKSERVICE account needs to have read permission to the private key. This is typically a common requirement when using certifcates for https.

At first we were using a bunch of scripts from the Windows SDK. The scripts were written in VBScript and although they worked, they were not as clean as the rest of the project. Something had to be done.

The VBScripts used CAPICOM's COM API. CAPICOM does the trick and can be redistributed. So out came, ahem, Windows PowerShell.

First i needed to view the certificates.

dir certs:\localmachine\my

This does the trick, doesn't use CAPICOM and is built-in.

As an experiment I created the following which does the same thing:

function Get-Certificate
{

param([string]$certStore)
$store = new-object -com "CAPICOM.Store"
$store.Open(1,"$certStore",130)
$store.Certificates
$Store.Close()

}

Get-Certificate "my"

Shows the same certificates as the previous powershell command

Next i needed a way to add certificates to the store. This turned out to be easy.

function Add-Certificate
{

param([String]$certPath,[String]$certStore)
$store = new-object -com "CAPICOM.Store"
$store.Open(1,"$certStore",130)
$store.Load($certPath)
$store.Close()

}

To add a certificate to the "my" store you would enter:

Add-Certificate "path_to_cert.pfx" "my"

Next the permissions need to be set on the private key file.

function set-CertificateSecurity
{

param([String]$certName)
$keypath = $env:ProgramData + "\Microsoft\Crypto\RSA\MachineKeys\"
$store = new-object -com "CAPICOM.Store"
$store.Open(1,"my",130)
$certToSecure = $store.Certificates | where { $_.subjectname -like "*$certName*" }
$keyname = $certToSecure.PrivateKey.UniqueContainerName
if ($keyname -is [Object])
{ icacls $keypath$keyname /grant networkservice:RX }
$store.Close()

}

And finally a way to remove the certificates:

function Remove-Certificate
{

param([String]$certName,[String]$certStore)
$store = new-object -com "CAPICOM.Store"
$store.Open(1,"$certStore",130)
$certToDelete =( $store.Certificates | where { $_.SubjectName -like "*$certName*" })
if ($certToDelete -is [Object])
{
if ($certToDelete.PrivateKey -is [Object])
{
$certToDelete.PrivateKey.Delete()
$store.Remove($certToDelete)
}
}
$Store.Close()

}

The scirpt that uses these commands looks like this:

Remove-Certificate "adatum" "root"
Add-Certificate "c:\dinnernow\scripts\install\certs\adatum.sst" "root"
add-certificate "c:\dinnernow\scripts\install\certs\www.fabrikam.com.pfx" "my"
set-certificatesecurity "fabrikam" "my"

This is another great way you can use Windwos PowerShell to reduce complexity and wrap some procedure into a nice reusable cmdlet. These scripts are just enough to do the job we needed, use these as a starting point for your own.

THIS POSTING IS PROVIDED "AS IS" WITH NO WARRANTIES, AND CONFERS NO RIGHTS