One of the great features of the Windows Enterprise issuing CAs, is the auto-renew option that you can set for your certificates.
BUT, when renewal time rolls around, how do you know if it’s worked? Or more specifically, are you just sitting around hoping that the auto-renewal worked and nothing breaks?
In my scenario, all servers are set to receive certificates (auto-enroll), and also to have those certificates auto-re-enrolled to reduce administrative overhead. And I needed an automated/scripted way to confirm that the auto-renewal had happened on every server (logging into every server and opening the Certificates MMC snap-in seemed like a lot of work for 500+ servers ).
The script below queries Active Directory for a list of servers (enabled and seen within the last 90 days), and then remotely checks its certificates in the Computer\Personal store.
My criteria for “the server certificate been correctly re-enrolled” was:
- Has a certificate with the same DNS name attached, that exactly matches the servers own FQDN, and;
- The certificate was valid for at least 90 days into the future (this is easily changed in the script if you need something different)
You might want to add a check for the issuing CA server name or something else to really make sure – but this was enough proof for my scenario – adjust to suit your needs.
The script below assumes you have the AD PowerShell module installed, and your internal firewall/Windows Firewall rules allows remote access to each server.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# Set variables $outputfile = "d:\temp\certreport.csv"; $today = get-date; $90dayfuture = (get-date).adddays(90); # Get enabled servers from AD $servers = get-adcomputer -filter {(operatingsystem -like "*server*") -and (enabled -eq $true)} -properties enabled, lastlogondate, operatingsystem; # Reduce server list to only include those with recent last logon dates $servers = $servers | where {($_.lastlogondate -ne $null) -and ($_.lastlogondate).adddays(90) -gt $today}; # Loop through each server found foreach ($server in $servers) { write-host "[STATUS] Contacting" $server.name try { # Get certs from the remote Personal store $certs = invoke-command -computername $server.name -scriptblock {get-childitem cert:\localmachine\my} write-host "[STATUS] Checking certs" $currentcert = $false; # Loop through all certs found foreach ($cert in $certs) { # Set flag if a valid cert is found if (($cert.dnsnamelist.unicode -eq $server.dnshostname) -and ($cert.notafter -gt $90dayfuture)) { $currentcert = $true } } if ($currentcert) { write-host "[SUCCESS] Valid certificate found on" $server.name -foregroundcolor "green"; } else { write-host "[SUCCESS] No valid certificates found on" $server.name -foregroundcolor "orange"; } # If the remote execution fails to connect (for any reason) } catch { $currentcert = "FAILED TO RETRIEVE"; write-host "[FAILED] Failed to connect to" $server.name -foregroundcolor "RED"; } # Crete CSV format for output (servername^TRUE/FALSE/FAILED TO RETRIEVE) $outline = $server.name + "^" + $currentcert; write-host "[STATUS] Writing output to" $outputfile; # Append output server result to CSV $outline >> $outputfile; } |
Apart from the CSV that gets created, I added some basic status messages on the screen (more of a sanity check for myself than anything else), which looks like this: