The ServerCertificateValidationCallback property of ServicePointManager does not work as expected in PowerShell Core. Attempts to assign and use a script block may result in an error being displayed, as shown here, when making a web request:
PS> [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
PS> [System.Net.WebClient]::new().DownloadString('https://expired.badssl.com/')
Exception calling "DownloadString" with "1" argument(s): "The SSL connection could not be established, see inner exception. There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: $true "
At line:1 char:1
+ [System.Net.WebClient]::new().DownloadString('https://expired.badssl. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
The SslStream type (System.Net.Security.SslStream) offers a potential alternative for capturing detailed certificate validation information. The method used in the following example works in both Windows PowerShell and PowerShell Core.
This example converts certificate validation information using Export-CliXml. Assigning the parameters to a global variable is possible, but certain information is discarded when the callback ends, including the elements of the certificate chain:
$remoteCertificateValidationCallback = {
param (
[Object]$sender,
[System.Security.Cryptography.X509Certificates.X509Certificate2]$certificate,
[System.Security.Cryptography.X509Certificates.X509Chain]$chain,
[System.Net.Security.SslPolicyErrors]$sslPolicyErrors
)
$psboundparameters | Export-CliXml C: empCertValidation.xml
# Always indicate SSL negotiation was successful
$true
}
try {
[Uri]$uri = 'https://expired.badssl.com/'
$tcpClient = [System.Net.Sockets.TcpClient]::new()
$tcpClient.Connect($Uri.Host, $Uri.Port)
$sslStream = [System.Net.Security.SslStream]::new(
$tcpClient.GetStream(),
$false, # leaveInnerStreamOpen: Close the inner stream when complete
$remoteCertificateValidationCallback
)
$sslStream.AuthenticateAsClient($Uri.Host)
} catch {
throw
} finally {
if ($tcpClient.Connected) {
$tcpClient.Close()
}
}
$certValidation = Import-CliXml C: empCertValidation.xml
Once the content of the XML file has been loaded, the content may be investigated. For example, the certificate that was exchanged can be viewed:
$certValidation.Certificate
Or, the response can be used to inspect all of the certificates in the key chain:
$certValidation.Chain.ChainElements | Select-Object -ExpandProperty Certificate
The ChainStatus property exposes details of any errors during chain validation:
$certValidation.Chain.ChainStatus
ChainStatus is summarized by the SslPolicyErrors property.
PowerShell should be restarted to reset the certificate policies to system defaults.