Exchange Certificate Reporting


powershellA quick tip on retrieving the expiration of certificates configured on your Exchange servers. While some certificate providers like DigiCert will proactively notify you when certificates are expiring in the near future, you may want to run such a report yourself. Or perhaps you want to verify configured certificates on all your Exchange servers are aligned.

To accomplish this, you could use readily available scripts, such as this one published by fellow MVP Paul Cunningham. But with some PowerShell you could easily construct yourself a one-liner which will perform the same task. We will first show the one-liner, after we will dissect and talk you through it. Note that being a lazy typist, I used several aliases to make the whole command a bit shorter, but not a lot.

Command
A command to retrieve basic certificate reporting for Exchange servers in your environment is as follows (wrapped for readability):

$D=(Get-Date).AddDays(30); Get-ExchangeServer | %{$S=$_.Identity;$R=$_.ServerRole; Get-ExchangeCertificate -Server $S |
Sort NotAfter | Select @{n='Server';e={'{0} ({1})' -f $S,$R}},
@{n='CertSubject';e={($_.Subject -split '( , )*..=')[1]}},
@{n='Expires';e={'{0:MM/dd/yyyy}' -f $_.NotAfter}},
@{n='IssuedBy';e={($_.Issuer -split '(, )*..=')[1]}},
@{n='Domains';e={$_.CertificateDomains -join ','}},
@{n='Alert';e={' !'[(Get-Date $_.NotAfter) -le $D]}},*} |
ft -a Alert, CertSubject, Status, Expires, IsSelfsigned, IssuedBy,
Services, Thumbprint, Domains -GroupBy Server | Out-String -Width 8192

Sample output
image

Dissection

$D=(Get-Date).AddDays(30) | Get-ExchangeServer

First, we want get a visual indication of certificates expiring in the coming 30 days. The command is followed by a semi-colon, which can be used to separate commands on the same line. The first cmdlet in our pipeline is Get-ExchangeServer, which returns all Exchange server objects.

%{$S=$_.Identity;$R=$_.ServerRole; Get-ExchangeCertificate -Server $S | Sort NotAfter | Select @{n='Server';e={'{0} ({1})' -f $S,$R}}, @{n='CertSubject';e={($_.Subject -split '( , )*..=')[1]}}, @{n='Expires';e={'{0:MM/dd/yyyy}' -f $_.NotAfter}}, @{n='IssuedBy';e={($_.Issuer -split '(, )*..=')[1]}}, @{n='Domains';e={$_.CertificateDomains -join ','}},@{n='Alert';e={' !'[(Get-Date $_.NotAfter) -le $D]}},*}

We are passing every Exchange server object to ForEach (%). For each of these objects, we will perform the following tasks:

  • First, we store its current Identity ($S) and Serverrole ($R) property in variables for later usage. This, because if we create a calculated properties later on, we have no reference anymore to the Exchange object in the calculated field expression, as $_ will then contain the current object passed to Select (Select-Object).
  • Next, we retrieve all certificates from the Exchange server we are looking at using Get-ExchangeCertificate, and we pipe those certificate objects to sort to order them by expiration date.
  • We then create several calculated properties in the pipeline stream:
    • A property named Server will contain a formatted string consisting of the server Identity ($S) and its server roles ($R).
    • A property named CertSubject, containing the name of the subject, without the ‘CN=’ prefix.
    • A property expires with a formatted expiration string (NotAfter).
    • A property named Issues, containing the name of the issuer of the certificate, without the ‘CN=’ prefix.
    • A property Domains containing the SAN names of the certificate, separated by commas.
    • A property Alert, showing an exclamation mark when certificate expires (NotAfter) before the date determined earlier ($D).
    • All other certificate properties are also retained by finally selecting all properties (*).
ft -a Alert, CertSubject, Status, Expires, IsSelfsigned, IssuedBy, Services, Thumbprint, Domains -GroupBy Server | Out-String -Width 8192


Finally, we format the output by selecting and ordering properties using Format-Table (ft), auto-sizing (-a) columns. In addition to the previously added calculated properties, we also return the SelfSigned, Services and Thumbprint properties. Using the GroupBy parameter, we make Format-Table group the objects on a specific property, in this case Server. Because the output can be very wide we use Out-String, specifying a large width to generate output larger than the host session without wrapping or truncating output.