A piece of my work around PowerShell and IIS (or usefull things I've found on the web). Mostly some reminders for myself!

Q: How-to monitor if a SSL certificate expiration date is coming?
A: We can wait for the alert email from the SSL certificate provider. And -WhatIf! Yes, what if the registered email no longer exists, or for any reason you don’t receive the alert? And what about one of my main rules: if you want it done right, you’ve got to do it yourself!?
So let’s do it ourselves! There’s many examples on how to check a SSL certificate validity and especially SSL certificate expiration date. But most of all checks the certificate store through the PS-drive ‘CERT:\’; that could be good enough, but it’s not the way I wanted… I want to get the certificate(s) from a central monitoring server through a webrequest.

Ok, here we are:

 

<#
.SYNOPSIS
Check-SSL.ps1 - Gets SSL certificate expiration date
.DESCRIPTION
Check-SSL.ps1 - Gets SSL certificate expiration date and send an email alert if a defined threshold is exceeded.
.PARAMETER WebsiteURL
Defines the URL of the SSL certificate to check
Mandatory parameter
No default value.
.PARAMETER WebsitePort
Defines the website port of the SSL certificate to check
Default is 443.
.PARAMETER CommonName
Defines the CommonName (CN) of the SSL certificate to check
Default is the value of the WebsiteURL parameter.
.PARAMETER Threshold
Defines the threshold (in days). If the SSL certificate expiration date exceeded the threshold, an email alert is sent.
Default is 15.
.NOTES
File Name   : Check-SSL.ps1
Author      : Fabrice ZERROUKI - fabricezerrouki@hotmail.com
.EXAMPLE
PS D:\> .\Check-SSL.ps1 -WebsiteURL secure.zerrouki.com -Threshold 30
Performs a check of the expiration date for the SSL certificate that secures the website http://secure.zerrouki.com. If the certificate expires in less than 30 days, an email alert is sent.
#>
Param(
[Parameter(Mandatory=$true,HelpMessage="IP address or hostname to check")][string]$WebsiteURL,
[Parameter(HelpMessage="TCP port number that SSL application is listening on")][int]$WebsitePort=443,
[Parameter(HelpMessage="CommonName (CN) on certificate")][string]$CommonName=$WebsiteURL,
[Parameter(HelpMessage="The number of days after which an alert should be sent.")][int]$Threshold=15
)

$MailTo="recipient@mail.com"
$MailSubject="$WebsiteURL - SSL certificate will expire in $ValidDays days"
$MailFrom="sender@mail.com"
$SmtpServer="mailserver.example.com"
$MailBody=@"
<html><span style='font-family: Tahoma; font-size: 12px;' >Hi,<br />
<br />
the SSL certificate for the website "$WebsiteURL" will expire in $ValidDays days. You should conserder renewing it.<br />
<br />
----------------------------------------------------------------------------</span><br />
<span style='font-family: Tahoma; font-size: 10px;' >This is an automatically generated email, please do not reply.<br />&nbsp;<br /></span></html>
"@

Try {
$Conn = New-Object System.Net.Sockets.TcpClient($WebsiteURL,$WebsitePort)

Try {
$Stream = New-Object System.Net.Security.SslStream($Conn.GetStream())
$Stream.AuthenticateAsClient($CommonName)

$Cert = $Stream.Get_RemoteCertificate()

$ValidTo = [datetime]::Parse($Cert.GetExpirationDatestring())

Write-Host "`nConnection Successfull" -ForegroundColor DarkGreen
Write-Host "Website: $WebsiteURL"

$ValidDays = $($ValidTo - [datetime]::Now).Days

if ($ValidDays -lt $Threshold)
{
Write-Host "`nStatus: Warning (Expires in $ValidDays days)" -ForegroundColor Yellow
Write-Host "CertExpiration: $ValidTo`n" -ForegroundColor Yellow
Send-MailMessage -To $MailTo -Subject $MailSubject -From $MailFrom -SmtpServer $SmtpServer -Priority High -BodyAsHtml $MailBody
}
else
{
Write-Host "`nStatus: OK" -ForegroundColor DarkGreen
Write-Host "CertExpiration: $ValidTo`n" -ForegroundColor DarkGreen
}
}
Catch { Throw $_ }
Finally { $Conn.close() }
}
Catch {
Write-Host "`nError occurred connecting to $($WebsiteURL)" -ForegroundColor Yellow
Write-Host "Website: $WebsiteURL"
Write-Host "Status:" $_.exception.innerexception.message -ForegroundColor Yellow
Write-Host ""
}

Has to be scheduled, each day for example (obviously less the threshold!).
http://www.zerrouki.com/schedule-a-powershell-script-execution/

10 Comments
Mynd Krime
Mynd Krime

Fabrice,

Thanks for the script works great..only thing is that I’m not receiving $ValueDays in the email subject or body…Would this need to be done on the SMTP server itself?

Thanks

Fab
Fab

Hi,
this is probably because the variable name is ‘$ValidDays’, not ‘$ValueDays’.

Mynd Krime
Mynd Krime

Sorry, meant $ValidDays…..resolved it by putting the information from the email directly into the email process instead of reference.

Tony
Tony

‘$ValidDays’ doesn’t work on Email

Josef
Josef

Hello, looks like amazing script and exactly what im looking for. Thank you!
But unfortunately it doesnt work against certificates, which are not trusted by the machine running the script (e.g. if you want to monitor OWA certificates from many small business Exchanges, signed by their locals CAs’). It returns just “Remote certificate is invalid according to validation procedure”. Do you have any idea, how to overcome this one?

Fab
Fab

Hi,
I’m afraid this behavior is “by design”. The workaround would be to add the certificate issuer in your trusted store. This should already be the case in a corporate environment, otherwise it means that users will receive a warning when they connect to the corporate webmail, not very clean…

Josef
Josef

thanks for reply, thats what i feared.
I have found this code
[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

which shall set sthe scrit to ignore untrusted certs. It seems to work to others, but im unable to integrate this into your script (because mine PS sklil is almost zero 🙂
Is possible to add it? And if yes, then where?

Fab
Fab

That can/could be a way to workaround it…
But, have a look: http://blogs.technet.com/b/bshukla/archive/2010/04/12/ignoring-ssl-trust-in-powershell-system-net-webclient.aspx
It seems to have to be at a higher level than just the script, so it’s a really ugly solution…

T R
T R

Fabrice,

I recently came across your ‘Check-SSL’ powershell script, and want to say, great job!!!!!!!!

I do have one question, though; how would I go about scanning multiple Website URLs? For example, lets say I have 50 URL’s I want to scan at once.

Thanks for much for your work.

Fab
Fab

Hi, and thank you!
This script is just a basic example and as your need, in real life we need something more “sophisticated”.. 😉
My first thought is:
1. You convert the script into a function
2. You write a new script with you 50 URLs in an array
3. You call the function within a ForEach loop with all the URLs.

And because I think my above explanation isn’t really clear, let’s illustrate what I mean:
[sourcecode language=”powershell” wraplines=”false” collapse=”false”]
Function Check-SSL {
Param(
[Parameter(Mandatory=$true,HelpMessage="IP address or hostname to check")][string]$WebsiteURL,
[Parameter(HelpMessage="TCP port number that SSL application is listening on")][int]$WebsitePort=443,
[Parameter(HelpMessage="CommonName (CN) on certificate")][string]$CommonName=$WebsiteURL,
[Parameter(HelpMessage="The number of days after which an alert should be sent.")][int]$Threshold=15
)

$MailTo="recipient@mail.com"
$MailSubject="$WebsiteURL – SSL certificate will expire in $ValidDays days"
$MailFrom="sender@mail.com"
$SmtpServer="mailserver.example.com"
$MailBody=@"
<html><span style=’font-family: Tahoma; font-size: 12px;’ >Hi,<br />
<br />
the SSL certificate for the website "$WebsiteURL" will expire in $ValidDays days. You should conserder renewing it.<br />
<br />
—————————————————————————-</span><br />
<span style=’font-family: Tahoma; font-size: 10px;’ >This is an automatically generated email, please do not reply.<br />&nbsp;<br /></span></html>
"@

Try {
$Conn = New-Object System.Net.Sockets.TcpClient($WebsiteURL,$WebsitePort)

Try {
$Stream = New-Object System.Net.Security.SslStream($Conn.GetStream())
$Stream.AuthenticateAsClient($CommonName)

$Cert = $Stream.Get_RemoteCertificate()

$ValidTo = [datetime]::Parse($Cert.GetExpirationDatestring())

Write-Host "`nConnection Successfull" -ForegroundColor DarkGreen
Write-Host "Website: $WebsiteURL"

$ValidDays = $($ValidTo – [datetime]::Now).Days

if ($ValidDays -lt $Threshold)
{
Write-Host "`nStatus: Warning (Expires in $ValidDays days)" -ForegroundColor Yellow
Write-Host "CertExpiration: $ValidTo`n" -ForegroundColor Yellow
Send-MailMessage -To $MailTo -Subject $MailSubject -From $MailFrom -SmtpServer $SmtpServer -Priority High -BodyAsHtml $MailBody
}
else
{
Write-Host "`nStatus: OK" -ForegroundColor DarkGreen
Write-Host "CertExpiration: $ValidTo`n" -ForegroundColor DarkGreen
}
}
Catch { Throw $_ }
Finally { $Conn.close() }
}
Catch {
Write-Host "`nError occurred connecting to $($WebsiteURL)" -ForegroundColor Yellow
Write-Host "Website: $WebsiteURL"
Write-Host "Status:" $_.exception.innerexception.message -ForegroundColor Yellow
Write-Host ""
}
}

$urls = @("www.microsoft.com","www.google.com")

ForEach ($url in $urls)
{
Check-SSL -WebsiteURL $url
} # EndOf ForEach ($proxyItem in $proxies)
[/sourcecode]

Name*Email*WebsiteComment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top