Skip to content

Instantly share code, notes, and snippets.

@jstangroome
Last active May 19, 2026 17:40
Show Gist options
  • Select an option

  • Save jstangroome/5945820 to your computer and use it in GitHub Desktop.

Select an option

Save jstangroome/5945820 to your computer and use it in GitHub Desktop.
PowerShell script to retrieve the public X509 certificate from a remote TLS endpoint
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]
$ComputerName,
[int]
$Port = 443
)
$Certificate = $null
$TcpClient = New-Object -TypeName System.Net.Sockets.TcpClient
try {
$TcpClient.Connect($ComputerName, $Port)
$TcpStream = $TcpClient.GetStream()
$Callback = { param($sender, $cert, $chain, $errors) return $true }
$SslStream = New-Object -TypeName System.Net.Security.SslStream -ArgumentList @($TcpStream, $true, $Callback)
try {
$SslStream.AuthenticateAsClient('')
$Certificate = $SslStream.RemoteCertificate
} finally {
$SslStream.Dispose()
}
} finally {
$TcpClient.Dispose()
}
if ($Certificate) {
if ($Certificate -isnot [System.Security.Cryptography.X509Certificates.X509Certificate2]) {
$Certificate = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $Certificate
}
Write-Output $Certificate
}
@hertus

hertus commented Jan 23, 2020

Copy link
Copy Markdown

thanks

@msajeesh

msajeesh commented Sep 13, 2020

Copy link
Copy Markdown

This works perfectly but we have to enter server names manually..how to find out SSL certificate installed servers in a domain ?

ghost commented Nov 5, 2020

Copy link
Copy Markdown

great, thank you!

@euyuil

euyuil commented Jan 7, 2021

Copy link
Copy Markdown

Thanks! Do this work for SNI?

@jstangroome

Copy link
Copy Markdown
Author

@euyuil if line 23 $SslStream.AuthenticateAsClient('') is modified to pass a SNI host name instead of the empty string as its argument, it should work, but I have not verified.

@sahmedz11

Copy link
Copy Markdown

Is there a timeout value or validation of certificate?

@jstangroome

Copy link
Copy Markdown
Author

@sahmedz11 As it is currently written, the script will use default .NET timeouts. You can augment the script to set $TcpClient.ReceiveTimeout or .SendTimeout to manage timeouts during the TLS handshake. There is also $SslStream.ReadTimeout and .WriteTimeout which could be set, but I'm not sure if these apply during the AuthenticateAsClient() call.

To implement a custom TCP connection handshake timeout, significant changes would be required to replace $TcpClient.Connect(...) with $TcpClient.BeginConnect(...) instead and implement an AsyncCallback which is possible in PowerShell but not something I have tried.

The script also very explicitly does not perform any certificate validation, its purpose is to return the certificate for deeper inspection, valid or not. However you can modify the $Callback = { ... } line to capture and report any validation errors, or perform additional custom validation.

@ericcsinger

Copy link
Copy Markdown

Just wanted to say this is awesome, thanks!

@Grundel1979

Copy link
Copy Markdown

Thank you!. This is great!

@richardhicks

Copy link
Copy Markdown

Would it be possible to save the certificate to a file as well?

@jstangroome

Copy link
Copy Markdown
Author

@richardhicks you can call .Export(...) on the returned certificate object, specify the desired certificate file format as the argument, then pass the output bytes to Set-Content, e.g.:

$cert=(Get-RemoteSSLCertificate.ps1 foo.com)
Set-Content file.cer -Encoding Byte -Value $cert.Export('Cert')

Untested.

@richardhicks

Copy link
Copy Markdown

Thanks. I'll give it a try. Also, confirmed that adding the hostname to $SslStream.AuthenticateAsClient('') (e.g., $SslStream.AuthenticateAsClient('foo.example.net') works for sites configured with SNI.

@spawnmarvel

Copy link
Copy Markdown

Thanks

@scarson

scarson commented Sep 26, 2023

Copy link
Copy Markdown

I modified my copy of the script to write the certificate to file with:

$CertExportDirectory = 'C:\temp\'
$CertExportName = $ComputerName + '_Port' + $Port.ToString() + '.cer'
$FilePath = Join-Path $CertExportDirectory  -Child $CertExportName
Export-Certificate -Cert $Certificate -FilePath $FilePath

With output like "C:\temp\example.com_Port443.cer"

I also run a validation check with:
Test-Certificate $Certificate

You may want to set some of the non-default Test-Certificate parameters depending on use case.

@goadeff

goadeff commented Nov 1, 2023

Copy link
Copy Markdown

Any ideas how to adapt this for retrieval of the certificate used by a remote SQL server (i.e. port 1433)? The script hangs at $SslStream.AuthenticateAsClient('') when I try to use it this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment