If an SSL certificate expires on a web server, RD Gateway, or WSUS server, the service is usually no longer available. To avoid such situations, you should continually check the expiration of certificates. This can be done with a PowerShell script.

For web servers that are accessible via the public Internet, there are numerous online services that can check at regular intervals when certificates expire and then notify the webmaster in good time. In the company network, many monitoring tools can take over this task.

If you are limited to the onboard tools for this purpose, you can use PowerShell. With the help of a relatively simple script, all servers can be scanned for certificates that will soon reach their expiration date.

Retrieving all servers from the AD

The following example reads all computers running Windows Server from Active Directory and remotely accesses their certificate store under LocalMachinemy. It displays all certificates that expire in less than 14 days or that have already expired.

To prevent the script from hanging when a server is not reachable, the Test-Connection cmdlet checks whether the target host is online.

$cred = Get-Credential
$c = 0
$servers = Get-ADComputer -Filter "OperatingSystem -like 'Windows Server*'"
$servers | foreach{
 $p = ($c++/$servers.count) * 100
 Write-Progress -Activity "Checking $_" -Status "$p % completed" -PercentComplete $p;
 if(Test-Connection -ComputerName $_.DNSHostName -Count 2 -Quiet){
    Invoke-Command -ComputerName $_.DNSHostName -Credential $cred `
    {dir Cert:\LocalMachine\my | ? NotAfter -lt (Get-Date).AddDays(14)}
  }
}

If necessary, you could restrict the list of servers by specifying certain OUs with the SearchBase parameter; alternatively, you could read them from a text file.

Subscribe to 4sysops newsletter!

Interactive execution of the script to check the expiration date of certificates

Interactive execution of the script to check the expiration date of certificates

Conclusion

The script is intended for interactive execution and shows the progress of the operation with Write-Progress. You could, of course, also customize it to run as a Scheduled Task and be notified by email if a certificate is about to expire.

avataravatar
12 Comments
  1. Fred Beck 3 years ago

    This is great!

    BTW Script fails with errors looking for

    Cert:LocalMachinemy

    Your screenshot is slightly different from the script you posted

    Cert:LocalMachine\my

  2. Ramkumar 2 years ago

    Do we have to run the above script on AD server or we have to run this Script on all the servers individually ?

    • Wolfgang Sommergut 2 years ago

      You can run the script from any workstation with the PowerShell AD module installed.

  3. Florian Braune 2 years ago

    Hi Wolfgang,

    any chance to get the certs FriendlyName instead of the ThumbPrint?

    Thanks

  4. Ziv 2 years ago

    Hi Wolfgang

    Thanks for the script. It's awesome!

    I think it's worth adding a few more lines ( But I don't know how... )
    
    1. Find the CA who expired 30 days ago and / or expires within 30 days.
    2. Add a column of the certificate name.
    
    3. Assuming I did a scheduled task that run PS1
       How can I attach the results to the email?
       How to make it so that only if there is expire CA it will send mail?

     

    Thanks 

    B.R

    Ziv

  5. olivier 2 years ago

    Hi Wolfgang

    As always interresting post, some comments that i would like to be constructive

    • Don't use DOS command when an equivalent PS cmdlet exists (i.e.  dir)
    • Don't use alias (i.e. dir, ?)
    • Name parameters (i.e. NotAfter should be -Property NotAfter)
    • Avoid, as much as possible, one-liner code.
    • Use correct formating (Carriage return after a pipeline and indentation)

    Why these proposal ? your readers are not all powershell experts, but a wider audience. Aliases are fine when passing a command line, but it is not recommended to use them in scripts.  Naming parameter is recommended by the best practices. One-liner code is not always appropriate to debug. Correct formating makes the code more readable and understandable.

    then the code should be :

    Get-ChildItem -Path Cert:\LocalMachine\my |
        Select-Object -Property friendlyName, Thumbprint, Subject, NotAfter |
        Where-Object -Property NotAfter -LT (get-date).AddDays(-14)

    @Florian Brune : to meet your need, I've added the property FriendlyName to the output. Feel free to add/remove the properties you would like or not.

    regards

    Olivier

  6. Tony Manzi 1 year ago

    This is a great script, but how can I get this to output all the expired or expiring certs to a text file or something like that?

  7. Olivier 1 year ago

    Hi Tony,
    Look the line $servers| foreach …
    Just before this add $Output =
    By this way the output of the foreach loop, will be store in the var $Output
    After that just call $output and use the pipeline to export in a file with the file type you would like.
    i.e. : $Output | Out-File -FilePath or better (for a later use) Export-Csv -Path

    Of course you could also export in another type of files (.json, .html. .xml, .xlsx, .docx, .pdf and event more). Some file types with native cmdlets and some toher with additional Powershell modules.

    Hope this help you.
    Regards

    avatar
  8. Les Waggoner 1 year ago

    Very useful!
    I am creating a script to generate the expiring certificates and email them to our it department.
    I am creating a new user for this however, I have not figured out how to set the user up to run this script without making them a domain administrator.
    Any suggestions?

  9. Gene 2 months ago

    This works great for Personal certs on local computer.

    Is there a way to modify this script or a different method (Via a tool or PowerShell) to list all certificates (Personal, trusted root ca,…. ) that are expiring on the local computer?

    Thanks,
    George

  10. Olivier 2 months ago

    Hi Gene;
    Sure there is a way to do that.

    $AllCertContainers = Get-ChildItem -Path Cert:\LocalMachine
    $ExpiringCerts = foreach ($item in $AllCertContainers)
    {
    Get-ChildItem -Path Cert:\LocalMachine\$($item.Name) |
    Select-Object -Property friendlyName, Thumbprint, Subject, NotAfter |
    Where-Object -Property NotAfter -LT (Get-date).AddDays(-14)
    }
    $ExpiringCerts | Out-GridView
    $ExpiringCerts | Format-List
    $ExpiringCerts | Format-Table # or whatever

    Regards

Leave a reply

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account