Looking at PKI certificates using ConfigMgr (SCCM) Compliance Settings

I recently had a request for a way to determine if a specific PKI certificate was installed on clients or not.  To accomplish this task, I decided the easiest method would be to create a simple PowerShell script which would check for the existence of the certificate, and then use the infinitely powerful Compliance Settings feature of Configuration Manager to run the script and report back the results.

First, here's a snip of the details of a sample certificate I wanted to check for.  Notice that the Issuer is "russlab-LABHOST-CA".  You could check the certificates Issuer, Subject, or any other property, but in my case, I'm going to look for the Issuer.

You have two options for running PowerShell scripts on clients, one is to sign the script with a trusted certificate, and the other is to set the PowerShell execution policy to "Bypass".  In my example, I won't be signing my PowerShell script, so I will go into Administration->Client Settings and select the default or create a new Client Settings.  Then go into the "Computer Agent" section of the client settings, and set the PowerShell execution policy to "Bypass".  This allows unsigned PowerShell scripts to execute when executed by the Computer Agent.  If you don't use the default client settings, you'll also need to make sure the custom client settings you created are also deployed to the collection you will be checking compliance on.

Now, go to Assets and Compliance->Compliance Settings->Configuration Items and click "Create Configuration Item".  The Create CI Wizard will appear.  Give it a meaningful name, select any categories if desired, and click "Next".

Select which operating systems are applicable and click "Next"

Click "New" to add a new setting to the CI.

Give the setting a meaningful name, change the Setting type to "Script" and leave the Data type "String".  Then click "Add Script"

Here's the PowerShell script I created for this demonstration.  It first sets a variable called "Compliance" to a value of "Compliant".  This way, if the certificate does NOT exist, we will call the machine compliant.  If the certificate DOES exist, we will set the Compliance variable to "Non-Compliant".  This assumes you do not want this certificate to be on any client.  If you want to make sure the cert IS on the clients, you can either flip things around in the script, or set the string to "Non-Compliant" instead of "Compliant" in the upcoming step.  You can massage the $Check = line to meet your specific needs.  The next line says if the results of the $Check has any data in it, set the variable $Compliance to "Non-Compliant".  Otherwise, it will still be set to "Compliant" because of the first line.  Finally, we echo out the value of $Compliance so ConfigMgr has something to go on.

Here it is again in copy/paste friendly format:

$Compliance = 'Compliant'
$Check = get-childitem -path cert:\localmachine -recurse | where-object {$_.Issuer -like '*RussLab*'}
If ($Check) {$Compliance = 'Non-Compliant'}
$Compliance

Now that you've pasted the script in, click the "Compliance Rules" tab and click "New" to add a new rule.

Give the rule a meaningful name, and put the word "Compliant" into the values.  As mentioned earlier, if you want to make sure the cert DOES exist on the machine, change this to "Non-Compliant" instead.  Select a severity level for Noncompliance and click "OK".

Next, Next through the wizard until the CI wizard completes.

Now go to Configuration Baselines and click "Create Configuration Baseline"

Click "Add", and select "Configuration Items"

Add the CI you just created, select any assigned categories if you wish, and click "OK" a couple of times until the Create Baseline wizard completes.

Now, right-click the new Configuration Baseline you just created and select "Deploy".

Click "Browse" and select the collection you want to check for the existence of the certificate on.  Select a schedule of how often you want to check the clients.

Click OK to complete the Deploy Configuration Baselines wizard.

Now, initiate a Machine Policy Retrieval on your test client to speed things along a bit, and then go to the Configuration tab.  Once it appears, click the ''Evaluate" button to once again speed things along a bit.

As you can see, it will come back with either Compliant or Non-Compliant.  In my demo, it came back as Non-Compliant because I didn't want the certificate to exist on my clients, but it does exist.

Now, you can also run a built-in report like "Summary compliance by configuration baseline" or another preferred report.

Voila!  Now I know that my client has the certificate on it that I don't want it to have!

Now, what if you want to verify that you have your "ConfigMgr Client Certificate" on all your clients before enabling HTTPS across the board?  The challenge with this is if you followed the directions on TechNet to a T, you don't have any friendly name to search on, and only the certificate template is something unique to look for.

A script like the one below pasted into your CI will accomplish this verification (assuming you named your ConfigMgr Client Certificate template the same as mine if you followed https://technet.microsoft.com/en-us/library/gg682023.aspx#BKMK_client2008_cm2012 to create your ConfigMgr client certificate templates.  If not, just modify the Template –eq line to meet your needs to match your template.)

$cert
=
Get-ChildItem
Cert:\localmachine\My
|

% {

$_
|
Select `

Friendlyname,

Thumbprint,

@{N="Template";E={($_.Extensions |

?{$_.oid.Friendlyname -match
"Certificate Template Information"}).Format(0) `

-replace
"(.+)?=(.+)\((.+)?", '$2'}},

@{N="Subject";E={$_.SubjectName.name}}

}

foreach ($a
in
$cert)

{

if ($a.Template -eq
"ConfigMgr Client Certificate") {$Compliance
=
"Compliant"}

}

$Compliance

 

What if you want to just find out which web servers have Server Authentication certificates that are going to expire in 90 days? An important thing to note here is certificates with an issuer starting with CN=MS-Organization-P2P-Access need excluded since they are pushed from AzureAD, and they also have an "Intended purpose" of Server Authentication even though they're on a workstation OS.

$certchk
=
Get-ChildItem
-Path
Cert:\LocalMachine\My
|
Where-Object {$_.EnhancedKeyUsageList.FriendlyName -eq
"Server Authentication"
-and $_.Issuer -notlike
"CN=MS-Organization-P2P-Access*"} |
Select-Object
-Property
PSComputerName, Subject, @{n='ExpireInDays';e={($_.notafter – (Get-Date)).Days}} |
Where-Object {$_.ExpireInDays -lt
90}

If (!($certchk)) {$Compliance="Compliant"}

Else {$Compliance="Non-Compliant"}

$Compliance

 

Enjoy!