# Get-TCPCert # # Use Pipeline for list of Hostnames or IP-Addresses # # Pending: Check Revocation http://poshcode.org/1633 # Pending: Check Issuer http://poshcode.org/1633 # Pending: Check CN/SAN-Name # Pending: Parallelisierung # 20161115 inital Version 1.0 and 1.1 # 20181115 Added TLS 1.2 enforcement switch # 20190405 Anpassung bei SSLFail # 20210201 Handling of TLSHandshakeFail fixed, Stopwatch added, Details about DNS-Name and IP-Address # 20210212 Vorbelegung des RemoteHost mit tr.teams.microsoft.com, tlstimsMS aus Differenz, computername durch remotehost ersetzt, Result-Definition erweitert # 20220617 Addieren Rawdata # 20240112 Erweiterung um DnsNameList # 20240220 Erweiterung um Starttls [cmdletbinding()] param ( [Parameter(ValueFromPipeline=$True)] [string]$remotehost = "tr.teams.microsoft.com", # Teams Media Relay Service [uint16]$port=443, [long]$tcptimeout= 1000, # wait up to 1Sec for TCP Connection [ValidateSet($null,"","Default","TLS","TLS11","TLS12","TLS13","SSL3")] [string]$tlsmode="Default", [switch]$starttls =$false ) begin { set-psdebug -strict write-host "Get-TCPCert:Start" $stopwatch = [system.diagnostics.stopwatch]::new() } process { write-host "--- Processing $remotehost" -NoNewline #$result = "" | Select-Object datetime,remotehost,remotename,remoteip,Port,Status,SslProtocol,CipherAlgorithm,HashAlgorithm,KeyExchangeAlgorithm,CN,Subject,NotAfter,NotBefore,Issuer,Thumbprint,SerialNumber,SignatureAlgorithmFriendlyName,dnstimems,connecttimems,tlstimems,totaltimems $result = [pscustomobject][ordered]@{ datetime = ((get-date).ToUniversalTime().tostring("u")) remotehost = $remotehost remotename = $null remoteip = $null Port = $port Status = $null SslProtocol = $null CipherAlgorithm = $null HashAlgorithm = $null KeyExchangeAlgorithm = $null CN = $null DnsNameList = $null Subject = $null NotAfter = $null NotBefore = $null Issuer = $null Thumbprint = $null SerialNumber = $null SignatureAlgorithmFriendlyName = $null RawData = $null dnstimems = -1 connecttimems= -1 tlstimems= -1 totaltimems= -1 } $stopwatch.Restart() if ($remotehost -as [ipaddress]) { write-host " UseIP-NoDNS" $dnsanswer = $remotehost $remoteip = $remotehost } else { write-host " DNS: $($remotehost)" $dnsanswer = (Resolve-DnsName -Type A -name $remotehost)[-1] $remoteip=$dnsanswer.ipaddress $result.dnstimems = $stopwatch.ElapsedMilliseconds } $result.remotename =$dnsanswer.name $result.remoteip = $remoteip $stopwatch.Restart() #Create a TCP Socket to the computer and a port number $tcpsocket = New-Object Net.Sockets.TcpClient try { write-host " Connect to $($remoteip):$port" -nonewline #$tcpsocket.Connect($computername, $port) $asyncConnect = $tcpsocket.BeginConnect($remoteip, $port,$null,$null) # wait up to tcptimeout if ($asyncConnect.AsyncWaitHandle.WaitOne($tcptimeout, $False)) { } $result.connecttimems = $stopwatch.ElapsedMilliseconds } catch { $result.connecttimems = $stopwatch.ElapsedMilliseconds write-host $_.Exception.Message $result.Status = "ErrConnect" } #test if the socket got connected if(!$tcpsocket.connected) { write-host " NoConnection" -foregroundcolor red $result.Status = "NoConnection" $result.connecttimems = -1 } else { write-host " Connected" -ForegroundColor Green -NoNewline write-host " TCPStream" -NoNewline $tcpstream = $tcpsocket.GetStream() if ($starttls) { [system.io.streamreader]$streamreader = New-Object System.IO.StreamReader($tcpstream,[system.text.encoding]::ASCII) [system.io.streamwriter]$streamwriter = New-Object System.IO.StreamWriter($tcpstream,[system.text.encoding]::ASCII) $streamwriter.AutoFlush=$true try { Write-host "Wait1" -nonewline $line = $streamreader.readline() Write-Host "Got:$($line)" Write-Host "SendEHLO" $streamwriter.WriteLine("EHLO msxfaq.de") Write-Host "Wait2" -nonewline do { $line = $streamreader.readline() Write-Host "Got:$($line)" } while ($line.startswith("250-")) if (!$line.startswith("250 ")){ Write-Host "2 not found. Got:$($line)" -ForegroundColor Red } else { Write-Host " Send STARTTLS" $streamwriter.WriteLine("STARTTLS") $line = $streamreader.readline() Write-Host "Got:$($line)" } } catch { Write-Host "Unable to init STARTTLS" -ForegroundColor Red $_.Exception } } write-host " SSLStream" -NoNewline $sslStream = New-Object System.Net.Security.SslStream($tcpstream,$false,{$true}) # verification callback always true write-host " AuthenticateAsClient:$($tlsmode.ToString()) as $($remotehost)" -nonewline $certcol = new-object System.Security.Cryptography.X509Certificates.X509CertificateCollection try { switch ($tlsmode) { "SSL3" {$sslStream.AuthenticateAsClient($remotehost, $certcol, [System.Net.SecurityProtocolType]::Ssl3, $false)} "TLS" {$sslStream.AuthenticateAsClient($remotehost, $certcol, [System.Net.SecurityProtocolType]::tls, $false)} "TLS11" {$sslStream.AuthenticateAsClient($remotehost, $certcol, [System.Net.SecurityProtocolType]::Tls11, $false)} "TLS12" {$sslStream.AuthenticateAsClient($remotehost, $certcol, [System.Net.SecurityProtocolType]::tls12, $false) } "TLS13" {$sslStream.AuthenticateAsClient($remotehost, $certcol, [System.Net.SecurityProtocolType]::tls13, $false) } Default {$sslStream.AuthenticateAsClient($remotehost, $certcol, [System.Net.SecurityProtocolType]::SystemDefault, $false) } } $result.tlstimems = $stopwatch.ElapsedMilliseconds - $result.connecttimems $result.Status = "AuthTLS$($tlsmode)OK" $result.CipherAlgorithm = $sslStream.CipherAlgorithm $result.HashAlgorithm = $sslStream.HashAlgorithm $result.KeyExchangeAlgorithm = $sslStream.KeyExchangeAlgorithm $result.SslProtocol= $sslStream.SslProtocol write-host " AuthTLS$($tlsmode)OK" -ForegroundColor green -NoNewline } catch { $result.tlstimems = $stopwatch.ElapsedMilliseconds - $result.connecttimems write-host " TLSHandshakeFail" -ForegroundColor Yellow write-host "Exception Type: $($_.Exception.GetType().FullName)" -ForegroundColor Red write-host "Exception Message: $($_.Exception.Message)" -ForegroundColor Red $result.Status = "TLSHandshakeFail" $result.SslProtocol= "Fail" $result.CipherAlgorithm ="" $result.HashAlgorithm ="" $result.KeyExchangeAlgorithm = "" } if ($result.Status -eq "AuthTLS$($tlsmode)OK") { try { Write-host " ReadCert:" -nonewline $certinfo = New-Object system.security.cryptography.x509certificates.x509certificate2($sslStream.RemoteCertificate) $result.RawData = $certinfo.RawData write-host "Done" -NoNewline -ForegroundColor green } catch { Write-host " Unable to read Certificate" $result.Status = "NoCertFound" } if ($result.Status -ne "NoCertFound") { write-host " Parsing CN: " -NoNewline $result.Subject = $certinfo.Subject $result.CN = $certinfo.Subject.split(",") | Where-Object {$_.startswith("CN=")} $result.DnsNameList = $certinfo.DnsNameList Write-host "$($result.CN)" -ForegroundColor Magenta -NoNewline $result.NotAfter = $certinfo.NotAfter $result.NotBefore = $certinfo.NotBefore $result.Issuer = $certinfo.Issuer $result.Thumbprint = $certinfo.Thumbprint $result.SerialNumber = $certinfo.SerialNumber $result.SignatureAlgorithmFriendlyName = $certinfo.SignatureAlgorithm.FriendlyName if ($result.SignatureAlgorithmFriendlyName -eq "SHA1RSA") { $result.Status = "WarnSHA1" } elseif (( ($result.NotAfter) - (get-date)).totaldays -lt 0 ) { $result.Status = "Expired" } elseif (( ($result.NotAfter) - (get-date)).totaldays -lt 30 ) { $result.Status = "Warn30Day" } else { $result.Status = "OK" } } } $sslStream.Close() } write-host " CloseConnection" -NoNewline $tcpsocket.close() $result.totaltimems = $stopwatch.ElapsedMilliseconds + $result.dnstimems write-host " SendtoPipeline" -NoNewline $result write-host " Done" } end { $stopwatch.stop() write-host "Get-TCPCert:End" }