Use Configuration Manager 2012 Compliance Settings to check for the existence of a PKI certificate

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 2012 (formerly known as DCM or Desired Configuration Management in Configuration Manager 2007) 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.

image

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.

image

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”.

image

Select which operating systems are applicable and click “Next”

image

Click “New” to add a new setting to the CI.

image

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

image

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.

image

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.

image

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”.

image

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.

image

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.

image

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.

image

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.

image

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!

image

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

 

Enjoy!