Posts Tagged ‘powershell’

Managing Microsoft Certificate Authority Certificate Lifecycle using Powershell

Posted on the February 8th, 2011 under Powershell by

Why is it that Microsoft makes creating and issuing certificates from a Microsoft Certificate Authority (CA) so easy yet makes managing the certificate lifecycle (revocation, expiration, renewal) so difficult? In less than 30 minutes, somebody with a basic knowledge of Windows can successfully create and begin issuing digital certificates from an internal Microsoft CA. The problems start once an administrator realizes that issued certificates are very difficult to track and manage–using a largely manual process. For example, assume a certificate is issued to provide SSL over HTTPS for a web server. The certificate template is likely going to specify the certificate is good for at least two (2) years. When you least expect it two years pass and the certificate unexpectedly expires and causes a service outage. Now extrapolate a bit, consider an environment where you have hundreds of webservers and thousands of issued certificates. All of the sudden a “manual” process is no longer viable.

Microsoft surely must have provided a way to directly manage their CA implementation through script…right? Unfortunately they didn’t. Microsoft provides access to their CA through a command-line tool “certutil” and also minimally through COM. Management through COM is possible but likely a complicated endeavor for the non-programmer. Ideally, Microsoft would have provided an easily accessible API that’s consumable by VBScript or Powershell. However, with recent changes to the certutil command-line tool in Windows Server 2008, Windows Vista and Windows 7, and some quick Powershell magic a decent certificate management tool is possible.

The following Powershell script exports the full list of issued certificates from a Microsoft CA using certutil and saves the certificate information as a CSV file. The CSV file is then imported and each certificate is checked to see if it falls within the certificate expiration window (definable in script). An e-mail is generated that contains basic certificate information for certificates that fall within the expiration window. This script can be scheduled to run using Microsoft Task Scheduler. Remember, this will only work if run on a Windows Server 2008, Windows Vista or Windows 7 computer due to the “CSV” option only being available in later versions of certutil.

# variables
[string]$caServerName = "<your ca server name\ca name>"
[string]$caCertExportPath = "c:\Temp\certlist.csv"
[string]$smtpSender = "no-reply@your-domain.com"
[string]$smtpRecipient = "user@your-domain.com"
[string]$smtpServer = "<fqdn of SMTP server>"
[int]$daysUntilExpiry = 30
$expiringCerts = @()

function Send-EmailCertNotice ([string]$_certificateList) {
$MailMessage = @{
    To = $smtpRecipient
    From = $smtpSender
    Subject = @"
The following issued digital certificates will expire soon.
"@
    Body = @"
The following digital certificates issued by <your_company_name> will expire in the next ($daysUntilExpiry) days.
Please request a certificate replacement/renewal from <e-mail@your-domain.com> if the following certificates are still needed.
$_certificateList
NOTE: This notification is being sent by an automated certificate management process and
cannot receive reply e-mail. If you have any questions please contact <e-mail@your-domain.com>.
"@
    Smtpserver = $smtpServer
	BodyAsHtml = $false
    ErrorAction = "SilentlyContinue"
	}

Send-MailMessage @MailMessage

}

# export certs to CSV file
certutil -view -config $caServerName csv > $caCertExportPath

# load cert CSV into an array
$issuedCerts = Import-Csv $caCertExportPath
if ($issuedCerts.Length -gt 0) {
	foreach ($cert in $issuedCerts) {
		try {
			$certExpires = [datetime]$cert."Certificate Expiration Date"
			$cert."Certificate Expiration Date" = $certExpires
		}
		catch [Exception] {

		}

		if ($certExpires -gt $(Get-Date) -and $certExpires -lt $(Get-Date).AddDays($daysUntilExpiry)) {
# filter out EFS type certs.
			if ($cert."Certificate Template" -ne "EFS") {
				$expiringCerts += $cert
			}
		}
	}

	$bodyVal = $expiringCerts | Select-Object @{n="Certificate ID"; e="Request ID"},
	"Certificate Template", "Certificate Expiration Date", "Issued Common Name",
	"Serial Number" | Sort-Object "Certificate Expiration Date" | Out-String
	Send-EmailCertNotice $bodyVal

}