This is a place for Systems Administrators and IT Professionals to find and share ideas, solutions and templates. If you have something that helps you solve a problem, chances are it will help someone else too. So pay it forward and send an email to TheAgreeableCow at gmail. Full mudos to you!

Tuesday 22 July 2014

Sysadmin Modular Report for SSL Certificates (now with check for key size of 1024 bits)

The SysAdmin Modular Reporting framework provides a consistent, flexible data collection and reporting tool with 'traffic light' style alerts for your environment. Written in Powershell using an easy to follow style, the framework collates any number of user generated plugins (function scripts), into a single report for any Windows system supporting Powershell.

Learn about the framework in the new Quick Start Guide (pdf).

Getting started
  1. Download modules from GitHub links below*
  2. Save to a server with Active Directory Powershell Tools
  3. Customise Global_Variables.ps1 as required (variables apply to all modules)
  4. Customise Module_Variables.ps1 as required (variables apply to this module)
  5. Review the plugins (reorder, remove, update thresholds etc)
  6. Run the report  Get-SAMReport Certificates [Email/OnScreen]
Review the scripts on GitHub
*I encourage you to review and understand any script downloaded from the internet. Also ensure to "unblock" each .ps1 files (Right click | Properties | Unblock), to avoid the [D] Do not run [R] Run once [S] Suspend security prompts.


SAMReports can provide a very detailed look into the health of your environment. You can view the relevant data that has been gathered and quickly see any Warnings or Alerts based on your thresholds. The overall title of the report will reflect the worst result, so for example if there were 6 sections and only one showed a Warning, the report title will be coloured as a Warning.

The result is a rich report with clear status indicators giving you an instant overview and the details to back it up.

      Picture 1. Sample Report showing plugins for the stores in a typical certificate chain


The independent plugin system is very flexible and provides an easy way to only report on information that you need. The template style provides a consistent output, but also makes it easy to adapt or add new plugins. The warnings or alerts are based on a failed test or data falling outside of thresholds that you can define.

Each plugin can generate four types of output:
  • Results Text (html formatted)
  • Results Data (html formatted table)
  • Results Status (Alert, Warning, Good colour codes)
  • A File (either saved to the \output folder or included as an email attachment)

About the Certificates Module

UPDATE: The report now includes a check for a key length that is less than 2048 bits. 

The report will list details for all certificates in the relevant stores, for all of your servers. There is even an option to log and remove any expired certificates.

This is a list of the current plugins for the Certificates module, which cover the certificate stores for a typical certificate chain:
  • 00 Module Variables.ps1   (loads AD snap-in, sets server scope, log file location etc)
  • 01 List Personal Certificates.ps1
  • 02 List Intermediate Certificates.ps1
  • 03 List 3rd Party Root Certificates.ps1
  • 04 List Trusted Root Certificates.ps1
There are a number of variables you can customise to change the scope of what is shown in the report, such as:

#Reporting variables
$MaxDays = 1095
$WarnDays = 90
$AlertDays = 30
$WarnKeySize = 2048

#Certificate Store Properties
$StoreLocation = "LocalMachine" #"LocalMachine","CurrentUser"
$StoreName = "My"   #"My","CA","AuthRoot","Root"
$OpenFlag = "ReadWrite"  #"ReadOnly","ReadWrite"

#Purge Variable
$PurgeExpired = $False          #$True or $False
$PurgeDays = -90

This is the core of each script, to show how it collects info from each store and builds it into the main report.

#Create an Array and run query
$ResultsData = @()
foreach ($Server in $Servers) {
    if (Test-Connection -computername $Server -count 1 -quiet){
        $stores = New-Object System.Security.Cryptography.X509Certificates.X509Store("\\$Server\$StoreName",$StoreLocation)
        $Certificates = $stores.Certificates | Select FriendlyName, serialNumber, Issuer, Subject, PublicKey, @{Label="Expires";Expression={($_.NotAfter)}}, @{Label="Days";Expression={($_.NotAfter - (Get-Date)).Days}}
        Add-content -path $Logfile -value "Server: $Server"
        Add-content -path $Logfile -value "Store: $StoreLocation\$StoreName"
        Add-content -path $Logfile -value " "

        foreach ($Certificate in $Certificates) {
            #Build Report
            if ($Certificate.Issuer -ne $null -and $Certificate.days -lt $MaxDays){
                $obj = New-Object PSobject
                $obj | Add-Member -MemberType NoteProperty -name "Server" -value $Server
                $obj | Add-Member -MemberType NoteProperty -name "Name" -value $Certificate.FriendlyName
                $obj | Add-Member -MemberType NoteProperty -name "Issuer" -value $Certificate.Issuer
                $obj | Add-Member -MemberType NoteProperty -name "Subject" -value $Certificate.Subject
                $obj | Add-Member -MemberType NoteProperty -name "Key Size" -value $Certificate.PublicKey.key.KeySize
                $obj | Add-Member -MemberType NoteProperty -name "Expires" -value $Certificate.Expires
                $obj | Add-Member -MemberType NoteProperty -name "Days" -value $Certificate.Days
                $ResultsData += $obj

                # Update Text and Alert count based on your criteria
                $Name = $Certificate.FriendlyName
                $Days = $Certificate.Days
                $Size = $Certificate.PublicKey.key.KeySize

                if ($Days -lt 0){
                    $AlertText += "!RED!Alert: Certificate $Name on $Server has expired "
                    $AlertCount += $AlertCount.count + 1            
                elseif ($Days -lt $AlertDays){
                    $AlertText += "!RED!Alert: Certificate $Name on $Server is expiring in $Days days"
                    $AlertCount += $AlertCount.count + 1            
                elseif ($Days -lt $WarnDays){
                    $WarningText += "!ORANGE!Warning: Certificate $Name on $Server is expiring in $Days days"
                    $WarningCount += $WarningCount.count + 1        
                if ($Size -lt $WarnKeySize){
                    $WarningText += "!ORANGE!Warning: Certificate $Name on $Server does not meet minimum key size of $WarnKeySize"
                    $WarningCount += $WarningCount.count + 1            
            #Log and Purge Old Certs
            If ($PurgeExpired -eq $True){
                $Name = $Certificate.FriendlyName
                $Issuer = $Certificate.Issuer
                $Subject = $Certificate.Subject
                $Expired = $Certificate.Expires
                $Days = $Certificate.Days
                $SerialNumber = $Certificate.serialNumber
                if ($Certificate.Issuer -ne $null -and $Certificate.days -lt $PurgeDays){
                    Add-content -path $Logfile -value "Name: $Name"
                    Add-content -path $Logfile -value "Issuer: $Issuer"
                    Add-content -path $Logfile -value "Subject: $Subject"
                    Add-content -path $Logfile -value "Expired: $Expired"
                    Add-content -path $Logfile -value "Days: $Days"
                    Add-content -path $Logfile -value " "
                    $PurgeCert = $stores.Certificates.Find("FindBySerialNumber",$SerialNumber,$FALSE)[0]
                    $ExpiredCount += $ExpiredCount.count + 1
    Add-content -path $Logfile -value "$Server Completed (Purge = $PurgeExpired). $ExpiredCount expired certificates deleted."
    Add-content -path $Logfile -value "-------------------------------------------------------------------"
    Add-content -path $Logfile -value " "
    $ExpiredCount = 0

More Info

This is a community driven project if you have any suggestion or module scripts you have created, I would love to include them here - with full mudos to you of course.

See the main SysAdmin Modular Reports page for more details, including working with Scheduled Tasks and downloads for other modules.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^


  1. May I make a suggestion? I would think the certificate purge flags might want to -all- be set $false by default (several are currently set to $true in the code). I wasn't really expecting something advertised as a "reporting" tool make changes to my servers. Yes, my fault for not reviewing the code more closely, but when I found the first option set to $false, I assumed the rest would be as well...

    1. I can't emphasise enough how important it is to review and understand any script you download from the internet.

      The scripts were posted as I use them in production and you can take solace that any certificates deleted were expired for at least 3 months and were well and truly of no use (do have a look at the logs which shows all of the purged certificate details). Having said that, this is first and foremost a reporting tool and I agree that by default they should not make changes to your environment. All scripts have been updated and reposted accordingly.