Working With PowerShell and TLS
I found myself yet again dealing with PowerShell and trying to access a URL with the Invoke-WebRequest
Cmdlet against a site using a self signed certificate. I have had to solve this problem before and there are plenty of articles on how to do this. Unfortunately, it takes me too much time to sift through the articles in a Google search to find the correct ones (there are some solutions out there that don’t work) and so I thought I’d document the solution on my own blog so I know exactly where to go next time.
The benefit of doing this means that others might also benefit from my solution. I will also update this article if I run into other issues around PowerShell and TLS that would be useful to share.
Problem 1 - ‘Could not establish trust relationship for the SSL/TLS secure channel.’
When trying to connect to a site with the Invoke-WebRequest
Cmdlet that is using an invalid certificate which generally means one that is self signed or from a certificate authority that your system doesn’t trust you get an error similar to the following.
Invoke-WebRequest : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
To get around this problem we can add the below code to your script or working PowerShell session. This code does not make any permanent changes to the system and has to be rerun for each PowerShell session.
Add-Type @"
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public class ServerCertificateValidationCallback
{
public static void Ignore()
{
ServicePointManager.ServerCertificateValidationCallback +=
delegate
(
Object obj,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors errors
)
{
return true;
};
}
}
"@
[ServerCertificateValidationCallback]::Ignore();
Now try your request again and it should work.
Problem 2 - ‘Could not create SSL/TLS secure channel.’
The second problem I’ve run into is connecting to a site on Windows 7 with the Invoke-WebRequest
Cmdlet that is secured with TLS 1.2 and doesn’t support earlier protocols. The error that you get when this happens looks like the below.
Invoke-WebRequest : The request was aborted: Could not create SSL/TLS secure channel.
I sure wish that Microsoft had better error messages sometimes. That aside, the way to work around this is to include the following code to your script or PowerShell session. Again this code does not make any permanent changes to the system and has to be rerun for each PowerShell session.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Your request should now work.
I believe the root cause of this is that Windows 7 doesn’t have TLS 1.1 and 1.2 enabled by default and so the client and server are not able to agree on a protocol that they both support and thus connection aborts as it should. I’m not sure if you would run into this problem with newer versions of Windows as I believe they have the newer TLS version enabled by default.