Public/Get-WebCertificate.ps1

Function Get-WebCertificate {

    <#
 
    .SYNOPSIS
    Makes a web request to an HTTPS website and returns the certificate
 
    .DESCRIPTION
    Makes an HTTPS web request to a given website and port and returns an X509Certificate2 object.
    It will automatically try to connect on TLS1.2, TLS1.1, TLS1.0, SSL3 and SSL2 in that order until it successfully
    connects and pulls the certificate
 
    .PARAMETER FQDN
    The fully qualified domain name(s) of the web resource you wish to pull a certificate for.
 
    .PARAMETER Port
    The TCP/IP port that the resource is running on. This has a default of '443' if not specified.
 
    .EXAMPLE
    PS> Get-WebCertificate -FQDN google.com
 
    Thumbprint Subject
    ---------- -------
    FD226574BEC85E043AB2007917B9F636171D485C CN=*.google.com, O=Google Inc, L=Mountain View, S=California, C=US
 
    .EXAMPLE
    PS> Get-WebCertificate -FQDN tls-v1-0.badssl.com -Port 1010 -Verbose
 
    VERBOSE: Trying request using TLS1.2
    VERBOSE: Error pulling certificate using TLS1.2.
    VERBOSE: Trying request using TLS1.1
    VERBOSE: Error pulling certificate using TLS1.1.
    VERBOSE: Trying request using TLS1.0
    VERBOSE: Sucessfully pulled certificate using TLS1.0.
 
    Thumbprint Subject
    ---------- -------
    CA5308746C1E0644D63AF61BF581C72AF90C7095 CN=*.badssl.com, O=Lucas Garron, L=Walnut Creek, S=California, C=US
 
    .EXAMPLE
    PS> $Sites = "google.com","microsoft.com","apple.com"
    PS> Get-WebCertificate -FQDN $Sites -Port 443
 
    Thumbprint Subject
    ---------- -------
    FD226574BEC85E043AB2007917B9F636171D485C CN=*.google.com, O=Google Inc, L=Mountain View, S=California, C=US
    1E83B66D00F2445EFFA9B2DB51118A46943AA885 CN=*.microsoft.com
    768EE9DAE0D8C91E305FBD0DD738CBF1E92DDBF7 CN=www.apple.com, OU=Internet Services, O=Apple Inc., STREET=1 Infinite Loop, L=Cupertino, S=Ca...
 
 
    .EXAMPLE
    PS> "google.com","microsoft.com","apple.com" | Get-WebCertificate -Port 443
 
    Thumbprint Subject
    ---------- -------
    FD226574BEC85E043AB2007917B9F636171D485C CN=*.google.com, O=Google Inc, L=Mountain View, S=California, C=US
    1E83B66D00F2445EFFA9B2DB51118A46943AA885 CN=*.microsoft.com
    768EE9DAE0D8C91E305FBD0DD738CBF1E92DDBF7 CN=www.apple.com, OU=Internet Services, O=Apple Inc., STREET=1 Infinite Loop, L=Cupertino, S=Ca...
 
    #>


    [Cmdletbinding()]
    Param (

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [string[]]$FQDN,

        [Parameter()]
        [int]$Port = 443

    )

    Begin {

        #Set the information preference so calls to Write-Information appear in the console
        $InformationPreference = "Continue"
        
        #Specify a hash table of protocols. The keys are the friendly names, and the values are the
        #possible values defined for the System.Security.Authentication.SslProtols .NET type
        $AlgorithmTable = [Ordered]@{

            "TLS1.2" = "Tls12"
            "TLS1.1" = "Tls11"
            "TLS1.0" = "Tls"
            "SSL3"   = "Ssl3"
            "SSL2"   = "Ssl2"

        }

        #The number of seconds each attempt to connect for each protocol will last before giving up
        #and moving to the next protocol
        $CertificateRequestTimeout = 2

        #Outputs to the information stream and handles grammar based on the number of inputted $FQDNs
        If ($FQDN.Count -eq 1) {Write-Information "Requesting Certificate, please wait..."}
        If ($FQDN.Count -gt 1) {Write-Information "Requesting Certificates, please wait..."}

    }

    #Loops through each piped in FQDN
    Process {

        #Loops through each site in the FQDN array
        ForEach ($Site in $FQDN) {

            Write-Verbose "Attempting to pull certificate for $Site"

            #Resets the algorithm loop counter to 0
            $AlgorithmLoopCount = 0

            #Loops through each alorithm in the algorithm table. Since the hash table is ordered,
            #this is done in order from top to bottom
            ForEach ($Algorithm in $AlgorithmTable.GetEnumerator()) {

                #Incriment the algorithm loop counter by 1
                $AlgorithmLoopCount++

                Write-Verbose "Trying request using $($Algorithm.Key)"

                #Start a job that requests the certificate. Because the job is a separate PS process,
                #the module must be imported, and various arguments must be passed in.
                $Job = Start-Job -ScriptBlock {
                    
                    Import-Module "$($Args[0])\..\Private\Invoke-WebCertificateRequest.ps1"
                    Invoke-WebCertificateRequest -FQDN $args[1] -Port $args[2] -Algorithm $Args[3].value -ErrorAction SilentlyContinue

                } -ArgumentList $PSScriptRoot, $Site, $Port, $Algorithm

                Write-Verbose "Waiting for up to $CertificateRequestTimeout seconds."
                Wait-Job $Job -Timeout $CertificateRequestTimeout | Out-Null

                #Recieve the job into the certificate variable
                $Certificate = Receive-Job $Job

                #If the certificate is null (no certificate returned)
                If ($Certificate -eq $Null) {
                    
                    #If the current algorithm is the last in the algorithm table
                    If ($AlgorithmLoopCount -eq $AlgorithmTable.Count) {

                        Write-Verbose "No certificate returned. No further protocols to try."
                        Write-Warning "No certificate returned for $Site."
                        #Exit the function
                        Break

                    }

                    Else {
                    
                        Write-Verbose "No certificate returned trying the next protocol."
                        #Loop back up to the next algorithm in the algorithm table
                        Continue

                    }

                }

                #If a certificate is returned
                Else {
                    
                    #Output the certificate object
                    Write-Output $Certificate
                    #Exit the function
                    Break
                
                }

            }

        }

    }

    End {

    }

}