While I was doing research on how to read certificates in Powershell. I was mostly finding the same solutions over and over again.

Reading from multiple servers

I needed a script that was able to retrieve information of certificates of a couple of servers on the domain. ‘Invoke-Command’ seemed a little bit insecure. And you needed to allow running remote commands on every server you wanted to run your script.

Create a Powershell module called ‘Certificates.psm1’. You’ll be able to re-use and import the code below assuming you want to run some scripts with a different frequency.

The code is pretty much self-explanatory.

[string[]]$servers = “WEB01”, “WEB02”;  
[string[]]$storeLocations = “CurrentUser”, “LocalMachine”;  
[string[]]$storeNames = “AddressBook”, “AuthRoot”, “CertificateAuthority”, “Disallowed”, “My”, “Root”, “TrustedPeople”, “TrustedPublisher”;  
  
function Get-Certificates() {  
[System.Security.Cryptography.X509Certificates[]] $certificates = @();  
  
foreach ($server in $servers) {  
foreach ($storeLocation in $storeLocations) {  
foreach ($storeName in $storeNames) {  
$store = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store(“\\$($server)\$($storeName)”, $storeLocation);  
try {  
$store.Open(0);  
$certificates += $store.Certificates;  
} catch {  
Write-Output “Error opening certificate store $($server) $($storeLocation) $($storeName)”;  
continue;  
} finally {  
$store.Close();  
}  
}  
}  
}  
return $certificates;  
}  
  
Export-ModuleMember -Function Get-Certificates  

Retrieve certificates about to expire

param(  
[string]$Days = 90  
);  
  
Import-Module ./Certificates.psm1;  
  
$certificates = Get-Certificates;  
  
$expiringCertificates = $certificates | Where-Object {$\_.NotAfter -gt (Get-Date) -and $\_.NotAfter -lt (Get-Date).AddDays($Days)}  
  
if ($expiringCertificates.Count -gt 0) {  
  
$formattedOutputString = $expiringCertificates | Format-Table Thumbprint, Subject | Out-String;  
  
}

Retrieve certificates that are not SHA-256

You may want to find if there are less secure certificates on your server.

Import-Module ./Certificates.psm1;  
  
$certificates = Get-Certificates;  
  
$insecureCertificates = $certificates |  
Where-Object {$\_.SignatureAlgorithm.FriendlyName -and $\_.SignatureAlgorithm.FriendlyName -ne ‘sha256RSA’} |  
Select-Object -Property ‘DnsNameList’, ‘Subject’, @{  
Name = “Algorithm”  
Expression = {$_.SignatureAlgorithm.FriendlyName}  
}, @{  
Name = “KeyLength”,  
Expression = {$_.PublicKey.Key.KeySize}  
}, “NotAfter”, “NotBefore”;  
  
if ($insecureCertificates.Count -gt 0) {  
…  
}  

Scheduling your Powershell script

You can schedule your Powershell script with ‘Task Scheduler’. It’s good practice to run the script under a service account. When using a service account, you should make sure the account has ‘Logon as a batch’ permissions granted on the server where the Powershell script is scheduled. If you happen to forget this step, you’ll be reminded.