Category Archives: PKI

Retrieving certificates from ADCS (for securing credentials used in DSC resources)

If you need to specify credentials in a DSC resource and don’t want it to be stored in plain text (you don’t!) you need to encrypt it using the public key of a certificate. That overall process is described here, it is also shown in module 6 of the Getting Started with PowerShell Desired State Configuration (DSC) MVA event.

What I want to address with this post is the process of obtaining the public key and thumbprint of the certificate used for encryption. A lot of examples I’ve seen are following the basic concept of retrieving the certificate from the local server where the mof will be deployed, but that requires firewall openings to all servers and credentials to them, and I think this might be a better/simpler alternative to that, at least in some cases.

So I’ve written a function (link at the bottom of this post) that gets the information needed straight from a Microsoft Certificate Authority (aka Active Directory Certificate Services) instead of all the different servers, which I think simplifies the process a bit.

I’ve also added some other properties to the returned objects to make it possible to use this advanced function for monitoring expiring certificates.

I’ll give you some examples on how to use this function below!

I’d also like to point out that I found a lot of parts of this code on the internet, I’ve just added a few extra things to it and wrapped it in an advanced function. I’m not sure who is the original author of this code though, if anyone knows, please add a comment below so I can give credit where credit is due! Thanks to whoever you are! 🙂

So, the process itself is pretty straight forward, specify your CA instance and what certificates you are interested in and the function will return them for you. You could for example do this:

PS> Get-CACertificateDatabase -CertificationAuthority "contoso.com\Issuing CA" -IncludeBinaryCertificate

All issued certificates valid today and up to two years ahead will be returned, including their public key. To save them all to disk you could do this:

PS> Get-CACertificateDatabase -CertificationAuthority "contoso.com\Issuing CA" -IncludeBinaryCertificate | ForEach-Object { $_.BinaryCertificate | Out-File "$($_.IssuedCommonName).cer" -Encoding default }

You might want to filter the returned certificates on the template you use for encrypting credentials in DSC if you don’t want all your certificates saved locally.

I hope someone might find this useful! If you need help getting started with DSC, check the links at the top of this post.

The code for this function as been uploaded here.

Automate SCOM Gateway Certificate Renewal

When deploying SCOM (System Center Operations Manager) in a multi-forest environment, you use certificates to establish the trust between the servers. Since we have CA Servers in every domain, we started up with configuring autoenrollment for all the SCOM Gateway Servers, and made sure all the different CA servers were added to the trust-store of the central servers. (I will not go through that process now, if you want me to, leave a comment).

So autoenrollment now works, but that isn’t really enough, is it? We still need to configure the Gateway Server to actually switch to the new certificate when it arrives.

The tool Microsoft has given to us to do this is MOMCertImport.exe, but that tool gives you a pop-up that you actually need to click on… Not very “automatable”.

After some research, we could find that all this tool seems to do is to add the certificates serial number, backwards (in pairs), as a binary key in the registry. That is very automatable! 🙂

Before you start, you should know that this method is probably NOT supported by Microsoft, on the other hand, if it fails, you could run MOMCertImport.exe and see if that helps…

A code walkthrough follows:

Let’s start with setting up some user controlled variables, like what Certificate Template is used and where the registry key is located:

# Specify SCOM Template name
$SCOMTemplateName="SCOM Template"

# Specify SCOM Certificate Registry Key Path
$SCOMCertRegPath="HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Machine Settings"

# Specify SCOM Certificate Registry Value Name
$SCOMCertRegValueName="ChannelCertificateSerialNumber"

We then need a way of going through the certificates on the server to see if a new certificate has arrived:

# Initialize new array
$ParsedCertificates=@()

# List all local certificates
$LocalCertificates=Get-ChildItem Cert:\LocalMachine\My

# Go through the certificate and parse them to get the certificate template information out
foreach ($LocalCertificate in $LocalCertificates) {

$ParsedCertificates+= $LocalCertificate | Select `
Friendlyname,
Thumbprint,
SerialNumber,
NotAfter,
NotBefore,
@{Name="Template";Expression={($_.Extensions |
Where-Object {$_.oid.Friendlyname -match "Certificate Template Information"}).Format(0) -replace "(.+)?=(.+)\((.+)?", '$2'}},
@{Name="Subject";Expression={$_.SubjectName.name}}
}

As you can see, you need some regex to get the actual Certificate Template name. This should probably be turned into an advanced function! I might put that on a ToDo-list…

Now we have all the information we need to check if a new SCOM Gateway certificate has arrived.

I thought the easiest way of doing that was by getting the serial number of the latest certificate from that template, like this:

# Load the serial number of the newest SCOM Certificate into a new variable
$SerialNumber=($ParsedCertificates | Where-Object { $_.Template -eq $SCOMTemplateName } | Sort-Object NotAfter -Descending | select -First 1).SerialNumber

It’s now time for some regex-magic again, we want to pair this number up (2 and 2), and then reverse those pairs. I must confess I did a couple of rewrites of this before I found one that seems quite effective:

# Reverse the serial number to match the format in the registry
$ReversedPairs=[regex]::Matches($SerialNumber,'..','RightToLeft') | ForEach-Object { $_.Value }

The two dots (‘..’) tells powershell to group them, and the ‘RightToLeft’ reverses them. The last foreach is to get only the values and nothing else.
But it needed to be in binary format aswell, we achieve that by doing this:

# Convert string to binary
$ReversedPairsInBinary=$ReversedPairs | ForEach-Object { [convert]::ToByte($_,16) }

We now have something that we can compare with the current registry value, so let’s load the current one:

# Load current serial number into variable
$CurrentSCOMCertificate=Get-ItemProperty -Path $SCOMCertRegPath | Select-Object $SCOMCertRegValueName -ExpandProperty $SCOMCertRegValueName

And now let’s join the arrays and compare them, and based on the results update the registry if needed and restart the SCOM Gateway Service.

# Check if we have a new certificate
if (($ReversedPairsInBinary -join "") -eq ($CurrentSCOMCertificate -join "")) {
Write-Output "The current certificate is the latest."
}
else {
Write-Output "New certificate found. Changing registry..."
# Write to registry key
New-ItemProperty -Path $SCOMCertRegPath -Name $SCOMCertRegValueName -Value $ReversedPairsInBinary -Type Binary -Force

Write-Output "Restarting health service..."
# Restart the Health Service
Restart-Service -Name HealthService -Force
}

And we are done!

The complete and uncut code for this script is available here.

Good luck! 🙂