About this article
This article was created using an automated generation workflow leveraging generative AI. It reviews official .NET documentation for TcpClient, SslStream, and X509Certificate2, and consolidates the findings into a minimal example for reading the expiration date of a server certificate after a TLS connection.Verification Status: 📘 Confirmed with official .NET specifications – External TLS connection not yet executed
You can establish a TLS connection from PowerShell and check the Subject and expiration date of the presented certificate without opening a browser window. The key is to use the standard authentication flow of SslStream without disabling certificate validation.
Try it first
$hostName = 'www.microsoft.com'
$tcp = [Net.Sockets.TcpClient]::new()
$ssl = $null
try {
$tcp.Connect($hostName, 443)
$ssl = [Net.Security.SslStream]::new($tcp.GetStream(), $false)
$ssl.AuthenticateAsClient($hostName)
$cert = [Security.Cryptography.X509Certificates.X509Certificate2]::new(
$ssl.RemoteCertificate
)
[pscustomobject]@{
Host = $hostName
Subject = $cert.Subject
NotAfter = $cert.NotAfter
DaysLeft = [math]::Floor(($cert.NotAfter - (Get-Date)).TotalDays)
}
}
finally {
if ($null -ne $ssl) { $ssl.Dispose() }
$tcp.Dispose()
}
Look here
AuthenticateAsClient() after completing RemoteCertificate, then read DaysLeft represents the observed value of "how many days are left until NotAfter".
Why pass the host name
In TLS, not only the destination IP address but also "which host name to connect to" is important.AuthenticateAsClient($hostName) The host name in relates to TLS authentication using the server name.
sequenceDiagram
participant P as PowerShell
participant T as TcpClient
participant S as TLS Server
P->>T: host:443へ接続
T->>S: TCP接続
P->>S: AuthenticateAsClient(host)
S-->>P: 証明書を提示
P->>P: RemoteCertificateを読む
Change one part
www.microsoft.com Change github.com to
$hostName = 'github.com'
and compare how the Subject and NotAfter change. Even with the same code, changing the target changes the certificate information. This shows that you are not just "checking the expiration of port 443", but inspecting the certificate presented by the connection target.
Do not determine "healthy" based on expiration alone
Even if NotAfter is in the future, that alone does not guarantee that TLS is healthy. Other factors exist, such as name mismatches, trust chains, revocation, and TLS configurations.
Furthermore, on sites using a CDN or load balancer, you may actually be observing the certificate presented by the front-end service rather than the internal origin certificate.
For professional use
Proactively check for forgotten certificate renewals on internal web sites
Use as a minimal validation step before listing remaining days for multiple FQDNs
Cross-reference "certificates visible in the browser" with automated monitoring results
Record the actual presented Subject and NotAfter before contacting the vendor
When scaling this into monitoring, avoid treating a single failure as an expiration; instead, separately record where the failure occurred (DNS, TCP connection, TLS authentication, or certificate retrieval) for better practical usability.
Why cleanup is necessary
TcpClient and SslStream hold connection resources, so they must be disposed of using finally. Especially when expanding this into logic that iterates over multiple hosts, omitting cleanup can cause unnecessary retention of connection resources.
