PowerShell to get remote website’s SSL certificate expiration
I recently needed to put together a PowerShell script that would check the expiration of some external and internal certificates for my company and let me know when they are close to expiring. Since some of the hosts were IP addresses, and some certs were not trusted by the machine running the check, I had to have a way to disable certificate chain validation (equivalent to the curl option -k). There are many ways to get web content in PowerShell, and some are more flexible than others… After some poking around, I put together the script below, combining examples from this post and this post.
$minimumCertAgeDays = 60
$timeoutMilliseconds = 10000
$urls = @(
"https://www.website.com/Login.aspx",
"https://10.1.1.10/myTestPage.aspx"
) #disabling the cert validation check. This is what makes this whole thing work with invalid certs...
[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} foreach ($url in $urls)
{
Write-Host Checking $url -f Green
$req = [Net.HttpWebRequest]::Create($url)
$req.Timeout = $timeoutMilliseconds try {$req.GetResponse() |Out-Null} catch {Write-Host Exception while checking URL $url`: $_ -f Red} [datetime]$expiration = $req.ServicePoint.Certificate.GetExpirationDateString()
[int]$certExpiresIn = ($expiration - $(get-date)).Days $certName = $req.ServicePoint.Certificate.GetName()
$certPublicKeyString = $req.ServicePoint.Certificate.GetPublicKeyString()
$certSerialNumber = $req.ServicePoint.Certificate.GetSerialNumberString()
$certThumbprint = $req.ServicePoint.Certificate.GetCertHashString()
$certEffectiveDate = $req.ServicePoint.Certificate.GetEffectiveDateString()
$certIssuer = $req.ServicePoint.Certificate.GetIssuerName() if ($certExpiresIn -gt $minimumCertAgeDays)
{Write-Host Cert for site $url expires in $certExpiresIn days [on $expiration] -f Green}
else
{Write-Host Cert for site $url expires in $certExpiresIn days [on $expiration] Threshold is $minimumCertAgeDays days. Check details:`n`nCert name: $certName`nCert public key: $certPublicKeyString`nCert serial number: $certSerialNumber`nCert thumbprint: $certThumbprint`nCert effective date: $certEffectiveDate`nCert issuer: $certIssuer -f Red} rv req
rv expiration
rv certExpiresIn
}
Hope it saves someone some time… 🙂
2014/05/22 at 09:44
Great script. Thanks. For range use
$urls=@();$a=”https://192.168.12.”;for($i=1;$i -le 255;$i++){$urls+=($a+$i)}
2014/05/22 at 10:35
Nice snippet, thanks!
2014/07/14 at 14:20
How would you get the parent certificates?
2014/07/15 at 09:37
The $req object (and in particular $req.ServicePoint.Certificate) contains some data about the cert issuer, although it is rather limited. I have a feeling you may be looking for something different, possibly what is posted here. Let me know if that was not what you meant, I will try to help.
2015/01/11 at 23:40
Thanks! Very useful except that I get an error when it comes to pages requiring proxy.
Checking https://www.yahoo.com
Exception while checking URL https://www.yahoo.com: Exception calling “GetResponse” with “0” argument(s): “The remote se
rver returned an error: (407) Proxy Authentication Required.”
Do you have a workaround to make your script work through proxy?
2015/01/12 at 09:43
You can add credentials to the $req object, right below the “$req.Timeout = $timeoutMilliseconds” line, something like this:
$req.Timeout = $timeoutMilliseconds
$req.Credentials = new NetworkCredential($User, $Password, $Domain)
I can’t test it, since I don’t have a proxy that I can use, but that is a pretty standard way of doing it so I don’t think you will have issues.
2015/03/08 at 06:08
Cannot convert value “21/08/2015 23:59:59” to type “System.DateTime”. Error: “String was not recognized as a valid DateTime.”
At line:15 char:1
errrrr….bummer :-\
2015/03/08 at 06:42
I fixed your script.
just add the following after the “$expiration” declaration:
$a = $expiration
$d = [datetime]::ParseExact($a, “dd/MM/yyyy HH:mm:ss”, $null)
$expiration = $d
Cheers!
2015/03/10 at 20:34
works like a charm! Thanks so much. had to add some parsing for the date but that was all.
2015/03/10 at 20:42
Glad it helped!
2015/03/26 at 13:45
Thanks! Works perfectly.
2015/03/27 at 11:59
just for the record, this does NOT work if you get any other status codes than 200 OK
2016/07/20 at 13:50
[…] plus from every server in the Farm. The function that checks the Certificate was adapted from PowerShell to get remote website’s SSL certificate expiration […]
2016/07/21 at 10:46
Worked great for me and saved me a lot of time. Thank you.
2016/09/16 at 10:49
Hey is there any way to sort this by expiration date if I have multiple websites, I’m running this against?
2016/09/16 at 22:54
You could put each entry into a custom ps object and then sort it that way. Should be easy to find code snippets on the web for that.
2018/03/06 at 11:16
If the server may return a 302 redirect response, you can configure the request to not follow the redirect automatically, so you get cert info for the original URL, and not the redirect URL:
$req = [Net.HttpWebRequest]::Create($url)
$req.Timeout = $timeoutMilliseconds
$req.AllowAutoRedirect = $false #don’t follow redirect
2018/03/08 at 18:19
Nice, thanks for sharing!
2018/07/12 at 14:19
Hi,
I added:
$req.AllowAutoRedirect = $false
But it doesn’t work. I have one site which do 302 and the result is:
“Exception calling “GetResponse” with “0” argument(s):”
There is no difference between false and true.
Any advise?
2018/03/08 at 21:53
Hi This is a great script but has a flaw – if you live outside the US using the [datetime] will mess up the cert date and switch the days and months. I found a code snippet that takes the value from the cert and formats it correctly into the correct date
$minimumCertAgeDays = 60
$timeoutMilliseconds = 10000
$urls = @(
“https://”
)
#disabling the cert validation check. This is what makes this whole thing work with invalid certs…
[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
foreach ($url in $urls)
{
$req = [Net.HttpWebRequest]::Create($url)
$req.Timeout = $timeoutMilliseconds
try {$req.GetResponse() |Out-Null} catch {}
function Convert-StringToDateTime
{
param
(
[Parameter(Mandatory = $true)]
[String] $DateTimeStr
)
$DateFormatParts = (Get-Culture).DateTimeFormat.ShortDatePattern -split ‘/|-|\.’
$Month_Index = ($DateFormatParts | Select-String -Pattern ‘M’).LineNumber – 1
$Day_Index = ($DateFormatParts | Select-String -Pattern ‘d’).LineNumber – 1
$Year_Index = ($DateFormatParts | Select-String -Pattern ‘y’).LineNumber – 1
$DateTimeParts = $DateTimeStr -split ‘/|-|\.| ‘
$DateTimeParts_LastIndex = $DateTimeParts.Count – 1
$DateTime = [DateTime] $($DateTimeParts[$Month_Index] + ‘/’ + $DateTimeParts[$Day_Index] + ‘/’ + $DateTimeParts[$Year_Index] + ‘ ‘ + $DateTimeParts[3..$DateTimeParts_LastIndex] -join ‘ ‘)
return $DateTime
}
$expiration = Convert-StringToDateTime $req.ServicePoint.Certificate.GetExpirationDateString()
[int]$certExpiresIn = ($newdate – $(get-date)).Days
$certName = $req.ServicePoint.Certificate.GetName()
$certPublicKeyString = $req.ServicePoint.Certificate.GetPublicKeyString()
$certSerialNumber = $req.ServicePoint.Certificate.GetSerialNumberString()
$certThumbprint = $req.ServicePoint.Certificate.GetCertHashString()
$certEffectiveDate = $req.ServicePoint.Certificate.GetEffectiveDateString()
$certIssuer = $req.ServicePoint.Certificate.GetIssuerName()
if ($certExpiresIn -gt $minimumCertAgeDays)
{Write-Host Cert for site $url expires in $certExpiresIn days [on $expiration] -f Green}
else
{Write-Host Cert for site $url expires in $certExpiresIn days [on $expiration] Threshold is $minimumCertAgeDays days. Check details:`n`nCert name: $certName`nCert public key: $certPublicKeyString`nCert serial number: $certSerialNumber`nCert thumbprint: $certThumbprint`nCert effective date: $certEffectiveDate`nCert issuer: $certIssuer -f Red}
rv req
rv expiration
rv certExpiresIn
}
2018/03/09 at 06:32
Thank you for the enhancement!
2018/10/24 at 10:03
I ran into the same issue. I resolved by replacing
[datetime]$expiration = $req.ServicePoint.Certificate.GetExpirationDateString()
with
[datetime]$expiration = [system.datetime]::Parse($req.ServicePoint.Certificate.GetExpirationDateString())
Hope this helps
2018/07/23 at 14:44
Hi, greate scripts, and i got it working for couple of my servers, though on the third i get the following error in red in powershell.
“Cert for site https://www.website.com expires in -736897 days [on 05/03/2020 09:21:57] Threshold is 30 days. Check details:
”
I cannot understand, because all the certficates are actually valid, can anyone please shed some light on this for me.
Much appreciated
2018/08/17 at 14:27
I want the result to be send via email can you please help
2018/12/04 at 12:05
How would I export this to a .HTML file?
2018/12/04 at 16:28
Not sure how pretty you want it to look, but try the ConvertFrom-Html cmdlet
2019/06/30 at 04:42
Some adjusted version is here: https://ziembor.github.io/Test-GMERemoteX509Cert/
2019/06/30 at 05:50
Thanks for sharing!