A time ago, Windows PKI team posted an article about a tool that allows you to check web server SSL certificate: Verifying The SSL Certificate Expiration with a tool. Unfortunately, the download link is broken. I have this tool and uploaded it to my weblog: VerifySSLCertificate.

  • ZIP archive SHA1 hash: C633A3DC3E8A3AA6BDD714EABB925429076A160A
  • Executable SHA1 hash: A13CE031F5C1331785E87B62D1464C6260549EC0

The tool is very good, but what if you want to run the test against a bulk of servers? Any sort of automation and batching means some PowerShell stuff :). To provide administrators with such tool I wrote a PowerShell script, where you can test web server SSL certificate and it's status. You can export required fields to XML or CSV for future examination/audit. Let's go:

function Test-WebServerSSL {
[CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
        [string]$URL,
        [Parameter(Position = 1)]
        [ValidateRange(1,65535)]
        [int]$Port = 443,
        [Parameter(Position = 2)]
        [Net.WebProxy]$Proxy,
        [Parameter(Position = 3)]
        [int]$Timeout = 15000,
        [switch]$UseUserContext
    )
Add-Type @"
using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;
namespace PKI {
    namespace Web {
        public class WebSSLTest {
            public Uri OriginalURi { get; set; }
            public Uri ReturnedURi { get; set; }
            public X509Certificate2 Certificate { get; set; }
            //public X500DistinguishedName Issuer;
            //public X500DistinguishedName Subject;
            public string Issuer { get; set; }
            public string Subject { get; set; }
            public string[] SubjectAlternativeNames { get; set; }
            public bool CertificateIsValid { get; set; }
            //public X509ChainStatus[] ErrorInformation;
            public string[] ErrorInformation { get; set; }
            public HttpWebResponse Response { get; set; }
        }
    }
}
"@
    $ConnectString = "https://$url`:$port"
    $WebRequest = [Net.WebRequest]::Create($ConnectString)
    $WebRequest.Proxy = $Proxy
    $WebRequest.Credentials = $null
    $WebRequest.Timeout = $Timeout
    $WebRequest.AllowAutoRedirect = $true
    [Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
    try {$Response = $WebRequest.GetResponse()}
    catch {}
    if ($WebRequest.ServicePoint.Certificate -ne $null) {
        $Cert = [Security.Cryptography.X509Certificates.X509Certificate2]$WebRequest.ServicePoint.Certificate.Handle
        try {$SAN = ($Cert.Extensions | Where-Object {$_.Oid.Value -eq "2.5.29.17"}).Format(0) -split ", "}
        catch {$SAN = $null}
        $chain = New-Object Security.Cryptography.X509Certificates.X509Chain -ArgumentList (!$UseUserContext)
        [void]$chain.ChainPolicy.ApplicationPolicy.Add("1.3.6.1.5.5.7.3.1")
        $Status = $chain.Build($Cert)
        New-Object PKI.Web.WebSSLTest -Property @{
            OriginalUri = $ConnectString;
            ReturnedUri = $Response.ResponseUri;
            Certificate = $WebRequest.ServicePoint.Certificate;
            Issuer = $WebRequest.ServicePoint.Certificate.Issuer;
            Subject = $WebRequest.ServicePoint.Certificate.Subject;
            SubjectAlternativeNames = $SAN;
            CertificateIsValid = $Status;
            Response = $Response;
            ErrorInformation = $chain.ChainStatus | ForEach-Object {$_.Status}
        }
        $chain.Reset()
        [Net.ServicePointManager]::ServerCertificateValidationCallback = $null
    } else {
        Write-Error $Error[0]
    }
}

The code connects to a server by using provided host name, instantiates a SSL connection, retrieves actual SSL certificate and tests, whether the certificate is valid (full tests are performed, including revocation checking). The following parameters can be used:

  • -URL — specifies the remote web server address. You must specify only host name, without any protocol prefixes. The correct host name is something like this: www.domain.com. This is the only mandatory parameter. All other parameters are optional.
  • -Port — if remote web server is configured to use a custom port (default is 443), you can specify a port number to connect.
  • -Proxy — use this parameter to specify a web proxy address if you wish to use proxy.
  • -Timeout — the default connection timeout is set to 15 seconds. You can override the value, by specifying another value. Timeout value must be set in milliseconds. Say, 1 second timeout will be 1000 milliseconds and 20 seconds — 20000 milliseconds.
  • -UseUserContext — by default, the certificate must chain up to a trusted CA, which certificate is trusted by the computer (installed in Local Machine\Trusted Root CAs). If the root CA is trusted by only current user — a test will fail. You can use this switch to override the default behavior, so the test will succeed if a root CA is trusted only by current user.

Here are some examples:

[↓] [vPodans] Test-WebServerSSL signin.ebay.com


OriginalURi             : https://signin.ebay.com/
ReturnedURi             : https://signin.ebay.com/
Certificate             : [Subject]
                            CN=signin.ebay.com, OU=Site Operations, O=eBay Inc., STREET=2145 Hamilton Ave, L=San Jose,
                          S=California, PostalCode=95125, C=US, SERIALNUMBER=2871352, OID.2.5.4.15=Private Organization
                          , OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, OID.1.3.6.1.4.1.311.60.2.1.3=US

                          [Issuer]
                            CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com
                          /rpa (c)06, OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US

                          [Serial Number]
                            3EA2CB6BAC5BDED626A5AEA6D914E30C

                          [Not Before]
                            19.01.2011 2:00:00

                          [Not After]
                            24.01.2013 1:59:59

                          [Thumbprint]
                            9DB60558622A1FA3EF5C0683671751CFDA8C7253

Issuer                  : CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/r
                          pa (c)06, OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
Subject                 : CN=signin.ebay.com, OU=Site Operations, O=eBay Inc., STREET=2145 Hamilton Ave, L=San Jose, S=
                          California, PostalCode=95125, C=US, SERIALNUMBER=2871352, OID.2.5.4.15=Private Organization,
                          OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, OID.1.3.6.1.4.1.311.60.2.1.3=US
SubjectAlternativeNames : {DNS Name=signin.ebay.com, DNS Name=signin.ebay.at, DNS Name=signin.ebay.be, DNS Name=signin.
                          ebay.ca...}
CertificateIsValid      : True
ErrorInformation        :
Response                : System.Net.HttpWebResponse



[↓] [vPodans] Test-WebServerSSL trust.beeline.ru


OriginalURi             : https://trust.beeline.ru/
ReturnedURi             : https://trust.beeline.ru/
Certificate             : [Subject]
                            CN=trust.beeline.ru, OU=DIT, O=Vimpelcom, L=Moscow, S=Moscow, C=RU

                          [Issuer]
                            CN=Vimpelcom ExternalCA, O=Vimpelcom, C=RU

                          [Serial Number]
                            40C9BF400000000341D9

                          [Not Before]
                            02.02.2012 8:32:51

                          [Not After]
                            02.02.2013 8:42:51

                          [Thumbprint]
                            58FEEEC8676F7E2D106DEA4235B22AFC09086AEB

Issuer                  : CN=Vimpelcom ExternalCA, O=Vimpelcom, C=RU
Subject                 : CN=trust.beeline.ru, OU=DIT, O=Vimpelcom, L=Moscow, S=Moscow, C=RU
SubjectAlternativeNames :
CertificateIsValid      : False
ErrorInformation        : {PartialChain, RevocationStatusUnknown, OfflineRevocation}
Response                : System.Net.HttpWebResponse



[↓] [vPodans]

In the output you will see some important details: certificate subject, issuer and Subject Alternative Name (SAN) extension names. The most important fields are bolded: CertificateIsValid displays whether the certificate has passed or failed all certificate checks. If at least one test fails — detailed error information will be set to ErrorInformation property. In the current example, the second certificate failed revocation checking (revocation information is unavailable) and has partial chain (the chain is missing one or more CA certificate and they are not downloadable/reachable). If the server has expired certificate, you will see the following information in these two properties:

CertificateIsValid      : False
ErrorInformation        : {NotTimeValid}

The tool will return all certificate errors (not throwing only the first). Hope, you find the script helpful.


Share this article:

Comments:

artem
artem 13.02.2012 12:13 (GMT+2) Test remote web server SSL certificate

Why not use something like �Get-Certificate | Test-Certicate�? I bet you (or other guys) already have those functions. And if they don't work this way for some reason, it seems like a good opportunity to improve them, not reinventing the wheel.

Vadims Podans
Vadims Podans 13.02.2012 16:13 (GMT+2) Test remote web server SSL certificate

because the code runs against remote web servers. In many cases the certificate locally may look as valid, but from client perspective � not. For example, certificate name mismatch, trust issues, revocation checking and so on.

artem
artem 13.02.2012 19:25 (GMT+2) Test remote web server SSL certificate

So, why not make �Get-Certificate� so that it grabs it from those remove web servers? All as you did it here: Get-Certificate -Path "signin.ebay.com" -Port "443" -Proxy "someshithere.contoso.com" -ProxyPort "8080" -Timeout "100500" This should bring the remote certificate into the client-side perspective. Then pipe it to �Test-Certificate� which would obviously check it locally.

Vadims Podans
Vadims Podans 13.02.2012 22:32 (GMT+2) Test remote web server SSL certificate

Currently I haven't a good design for universal Test-Certificate (it useless to have a separate Test-Certificate cmdlet for SSL certificates only). Probably, in future, when I will have a better solution.

artem
artem 14.02.2012 22:59 (GMT+2) Test remote web server SSL certificate

why do you need a separate one? It should just accept output from Get-Certificate.

Vadims Podans
Vadims Podans 15.02.2012 00:34 (GMT+2) Test remote web server SSL certificate

Currently I have no idea how to create a universal Test-Certificate command.

artem
artem 15.02.2012 04:28 (GMT+2) Test remote web server SSL certificate

What is the input format your current implementation of Test-Certificate expects?

kalihto
kalihto 20.02.2012 20:29 (GMT+2) Test remote web server SSL certificate

Clear Explanation.

Michael Bradley
Michael Bradley 28.03.2012 04:45 (GMT+2) Test remote web server SSL certificate

THANK YOU! I have to sift through lots and lots of nodes and this is a LIFE Saver.

Tom Davidson
Tom Davidson 05.07.2012 03:03 (GMT+2) Test remote web server SSL certificate

I have my own personal CA whose cert I have installed into the Trusted Root CAs. This way I can simulate the signing process and test configurations without the need for expensive commercial CA signed certs all the time. However, when I run your function against a server configured in this way, I get the following: CertificateIsValid : False ErrorInformation : {RevocationStatusUnknown} Not knowing much about SSL certs & revocation, is there any way I can configure things up so your function will generate a CertificateIsValid status of True for my test environments?

Vadims Podans
Vadims Podans 05.07.2012 17:37 (GMT+2) Test remote web server SSL certificate

This is a big question. Revocation checking is one of the most (and complicated) subject in PKI. The most likely issue is that URLs in the certificate's CDP extension are not accessible from your client. Open the target certificate, and examine URLs in CRL Distribution Points extension.

Messala
Messala 31.08.2012 01:55 (GMT+2) Test remote web server SSL certificate

I wish output valid from and valid to to this script. Any Ideas?

Vadims Podans
Vadims Podans 31.08.2012 03:34 (GMT+2) Test remote web server SSL certificate

The script already outputs these values (as a part of the certificate). But you can add the following properties to object: public DateTime ValidFrom; public DateTime ValidTo; and in the code (within 'New-Object PKI.Web.WebSSL' hashtable) add the following lines: ValidFrom = $Cert.NotBefore; ValidTo = $Cert.NotAfter;

Hank
Hank 31.01.2013 04:28 (GMT+2) Test remote web server SSL certificate

I tried adding "pubic DateTime ValidTo;" and "ValidTo = $Cert.NotAfter;" and I'm getting this error: Add-Type : Cannot add type. The type name 'PKI.Web.WebSSL' already exists. At C:\Temp\PowerShell\Test-SSL.ps1:16 char:9 + Add-Type <<<< @" + CategoryInfo : InvalidOperation: (PKI.Web.WebSSL:String) [Add-Type], Exception + FullyQualifiedErrorId : TYPE_ALREADY_EXISTS,Microsoft.PowerShell.Commands.AddTypeCommand New-Object : Member "ValidTo" not found for the given .NET object. At C:\Temp\PowerShell\Test-SSL.ps1:56 char:19 + New-Object <<<< PKI.Web.WebSSL -Property @{ + CategoryInfo : InvalidOperation: (:) [New-Object], InvalidOperationException + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.NewObjectCommand FYI - renamed the function to Test-SSL. I'd like to be able to grab the URL, SANs, Issuer, and expiration. I can get all but the expiration.

Hank
Hank 31.01.2013 04:54 (GMT+2) Test remote web server SSL certificate

I tried adding "pubic DateTime ValidTo;" and "ValidTo = $Cert.NotAfter;" and I'm getting this error: Add-Type : Cannot add type. The type name 'PKI.Web.WebSSL' already exists. At C:\Temp\PowerShell\Test-SSL.ps1:16 char:9 + Add-Type <<<< @" + CategoryInfo : InvalidOperation: (PKI.Web.WebSSL:String) [Add-Type], Exception + FullyQualifiedErrorId : TYPE_ALREADY_EXISTS,Microsoft.PowerShell.Commands.AddTypeCommand New-Object : Member "ValidTo" not found for the given .NET object. At C:\Temp\PowerShell\Test-SSL.ps1:56 char:19 + New-Object <<<< PKI.Web.WebSSL -Property @{ + CategoryInfo : InvalidOperation: (:) [New-Object], InvalidOperationException + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.NewObjectCommand FYI - renamed the function to Test-SSL. I'd like to be able to grab the URL, SANs, Issuer, and expiration. I can get all but the expiration.

Vadims Podans
Vadims Podans 31.01.2013 05:29 (GMT+2) Test remote web server SSL certificate

When you modified C# signature, you need to restart PowerShell console.

Hank
Hank 01.02.2013 02:35 (GMT+2) Test remote web server SSL certificate

Thanks that did the trick! I really appreciate this script, it will help me tremendously!

Vadims Podans
Vadims Podans 01.02.2013 03:49 (GMT+2) Test remote web server SSL certificate

Also I would like to advice you to try the PSPKI module: http://pspki.codeplex.com/ The module has an improved version of this command.

Ravi
Ravi 03.05.2013 19:09 (GMT+2) Test remote web server SSL certificate

When I am trying to use it, it does not show anything on the screen, tried with and without -URL parameters

Vadims Podans
Vadims Podans 03.05.2013 21:03 (GMT+2) Test remote web server SSL certificate

Any errors there? The function should return an exception or the formatted output.

Hank
Hank 07.08.2013 07:18 (GMT+2) Test remote web server SSL certificate

Hi, I use this script to automatically verify certificate information in my environment. I've been able to use it to grab information in the certificate...but do you know how I might be able to get the OU value from the Subject string? Thanks in advance, Hank

Vadims Podans
Vadims Podans 07.08.2013 16:21 (GMT+2) Test remote web server SSL certificate

You can use regular expressions to extract OU information. Though regex may be a bit complicated, because there may be multiple OU attributes. Or split subject name to tokens: $RDNs = (Test-WebServerSSL signin.ebay.com).Subject.Split(",").Trim() and index to $RDNs to get desired RDN attribute.

Scott
Scott 14.08.2013 07:52 (GMT+2) Test remote web server SSL certificate

Seems the "https://$url`:$port" does not support the full uri path... For example... Redirects https:\\webserver - might redirect or produce a cert and https:\\webserver\folder - might redirect to a different place and produce a different cert in that case $ConnectString would produce https:\\webserver\folder:443 which produces a slew of errors... Exception calling "Create" with "1" argument(s): "Invalid URI: The hostname could not be parsed. At line:39 char:5 + $WebRequest = [Net.WebRequest]::Create($ConnectString) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : UriFormatException Not a show stopper and surely not the norm but thought I would let you know since I ran into it. Scott

Vadims Podans
Vadims Podans 14.08.2013 16:24 (GMT+2) Test remote web server SSL certificate

> Seems the "https://$url`:$port" does not support the full uri path... yes, currently it is not supported. You can fill a bug here: https://pspki.codeplex.com/workitem/list/basic

Lance
Lance 25.06.2014 01:26 (GMT+2) Test remote web server SSL certificate

Thanks for this script! I'm going to try and add some email functionality to it but it is awesome! Thanks again.

Bewq
Bewq 23.07.2014 09:16 (GMT+2) Test remote web server SSL certificate

This is awesome! Thank you!!!!!!!!

Derek Murawsky
Derek Murawsky 18.09.2014 05:49 (GMT+2) Test remote web server SSL certificate

I used your code to develop a tool which tests for the signature algorithm of a web server. Turns out SHA-1 is being phased out in November, so we needed to check approximately 500 websites. This made it much easier. Code available here if you want/need it. https://gist.github.com/derekmurawsky/1345e55699343ec4ea9c Thanks!

Mario
Mario 08.10.2014 04:34 (GMT+2) Test remote web server SSL certificate

PS C:\> Test-WebServerSSL ebay.com Exception calling "SendRequest" with "0" argument(s): "Object reference not set to an instance of an object." At C:\Windows\system32\WindowsPowerShell\v1.0\Modules\PSPKI\Client\Test-WebServerSSL.ps1:26 char:2 + $Response.SendRequest() + ~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : NullReferenceException

Vadims Podans
Vadims Podans 08.10.2014 06:53 (GMT+2) Test remote web server SSL certificate

I responded to you on CodePlex web site.

loler
loler 16.10.2015 13:47 (GMT+2) Test remote web server SSL certificate

Hi, thanks for you code, but i prefer to use the windows tool - VerifySSLCertificate, the download link is borken, could you renew it ?

Ken
Ken 22.08.2016 23:32 (GMT+2) Test remote web server SSL certificate

Your link to VerifySSLCertificate.zip is broken (404 not found).

Marcel de Haas
Marcel de Haas 18.10.2016 11:40 (GMT+2) Test remote web server SSL certificate

Hi,

the script seems to be broken on Win10 1607 / Powershell5. I'n not familiar with using .NET Namespaces directly so I cannot fix this myself...

New-Object : The value supplied is not valid, or the property is read-only. Change the value, and then try again.
At line:54 char:9
+         New-Object PKI.Web.WebSSLTest -Property @{
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [New-Object], Exception
    + FullyQualifiedErrorId : SetValueException,Microsoft.PowerShell.Commands.NewObjectCommand

Vadims Podāns
Vadims Podāns 24.10.2016 22:31 (GMT+2) Test remote web server SSL certificate

Please, open a report on issue tracker: https://pspki.codeplex.com/workitem/list/basic

Pasc
Pasc 13.02.2017 20:25 (GMT+2) Test remote web server SSL certificate

For PowerShell 5 (and likely 3+) you could remove the add-type at the beginning and replace the new-object line by the following

<PoSHCode>

        $ConnectionInformation = New-Object PSObject -Property ([Ordered]@{ 
            OriginalUri = $ConnectString; 
            ReturnedUri = $Response.ResponseUri; 
            Certificate = [Security.Cryptography.X509Certificates.X509Certificate2]$WebRequest.ServicePoint.Certificate; 
            Issuer = $WebRequest.ServicePoint.Certificate.Issuer; 
            Subject = $WebRequest.ServicePoint.Certificate.Subject; 
            SubjectAlternativeNames = $SAN; 
            CertificateIsValid = $Status; 
            Response = $Response; 
            ErrorInformation = $chain.ChainStatus | ForEach-Object {$_.Status} 
        })
        $ConnectionInformation.PSObject.TypeNames.Add("Indented.LDAP.ConnectionInformation")
        $ConnectionInformation

</PoSHCode>

Don't yet understand how it works, just capturing out of http://www.indented.co.uk/2015/03/31/testing-ldaps

Bennett
Bennett 07.12.2018 21:20 (GMT+2) Test remote web server SSL certificate

It appears that when a wildcard certificate is presented it assumes all subdomains as covered.

Example: Test-WebServerSSL -URL wrong.host.badssl.com
CertificateIsValid : True (Should be false)

Elen
Elen 13.08.2019 05:33 (GMT+2) Test remote web server SSL certificate

Hello,

I´m not a programmer unf. could you help me on a code for check ssl based url to have certification autority name, data created and will expire,please?

I appreciate your help!

om8000
om8000 06.12.2019 17:20 (GMT+2) Test remote web server SSL certificate

Test-WebServerSSL www.google.com
Test-WebServerSSL : Exception calling "GetResponse" with "0" argument(s): "The operation has timed out"
At line:1 char:1
+ Test-WebServerSSL www.google.com
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-WebServerSSL

om8000
om8000 06.12.2019 17:24 (GMT+2) Test remote web server SSL certificate

Why with some web pages this works ok, but with others I'm getting response (let's say for non-valid certificates).

How can I check for all sites with valid and non-valid certificates?

 

Test-WebServerSSL : Exception calling "GetResponse" with "0" argument(s): "The operation has timed out"
At line:1 char:1
+ Test-WebServerSSL www.google.com
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-WebServerSSL

-or-

New-Object : The value supplied is not valid, or the property is read-only. Change the value, and then try again.
At line:54 char:9
+         New-Object PKI.Web.WebSSLTest -Property @{
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [New-Object], Exception
    + FullyQualifiedErrorId : SetValueException,Microsoft.PowerShell.Commands.NewObjectCommand

 

 


Post your comment:

Please, solve this little equation and enter result below. Captcha