After using standard solutions for ignoring certificate verification, Invoke-RestMethod
is returning:
Invoke-RestMethod : A system error occurred and has been logged. Please try again later or contact your administrator.
I just noticed this failure today, so I think it has something to do with a Powershell update. By "standard solutions" I mean:
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
which stopped working a few months ago, and setting the callback properly in a C# type added to Powershell (description below in History).
Here is my environment:
> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.15063.674
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.15063.674
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Here is a little history so this question doesn't just get closed as a duplicate.
If you Google around or search StackOverflow you can find this question coming up with a few canned responses. However, today I noticed that all of the standard solutions aren't working anymore.
The standard error Powershell gives is:
Invoke-RestMethod : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
The standard answer given on forums everywhere is to use this command before you call Invoke-RestMethod
:
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
But if you're using an up to date version of Windows 10 / 2016 and Powershell, then your call to Invoke-RestMethod
will return:
Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
The explanation for why that happens is found on Huddled Masses blog. It can be summarized as:
Setting the ServerCertificateValidationCallback to a scriptblock won't work for an asynchronous callback (one that happens on a task thread), because the other thread won't have a runspace to execute the script on.
Originally, I had been solving that problem with this code:
if (-not ([System.Management.Automation.PSTypeName]"TrustAllCertsPolicy").Type)
{
Add-Type -TypeDefinition @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem)
{
return true;
}
}
"@
}
if ([System.Net.ServicePointManager]::CertificatePolicy.ToString() -ne "TrustAllCertsPolicy")
{
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}
But, that didn't work on Windows Server 2016, even though it was working fine on Windows 10. So, based on Huddled Masses I wrote this up to handle certificate validation callbacks in C# rather than a script block:
function Disable-SslVerification
{
if (-not ([System.Management.Automation.PSTypeName]"TrustEverything").Type)
{
Add-Type -TypeDefinition @"
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public static class TrustEverything
{
private static bool ValidationCallback(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors) { return true; }
public static void SetCallback() { System.Net.ServicePointManager.ServerCertificateValidationCallback = ValidationCallback; }
public static void UnsetCallback() { System.Net.ServicePointManager.ServerCertificateValidationCallback = null; }
}
"@
}
[TrustEverything]::SetCallback()
}
function Enable-SslVerification
{
if (([System.Management.Automation.PSTypeName]"TrustEverything").Type)
{
[TrustEverything]::UnsetCallback()
}
}
That worked really well for a long time, but just recently I started getting the following error back when I call Invoke-RestMethod
:
Invoke-RestMethod : A system error occurred and has been logged. Please try again later or contact your administrator.
I understand that a proper solution is just to deploy certificates, but often you just want to test things out without having to set up a proper PKIX.
Invoke-RestMethod is perfect for quick APIs that have no special response information such as Headers or Status Codes, whereas Invoke-WebRequest gives you full access to the Response object and all the details it provides.
To bypass SSL certificate validation for local and test servers, you can pass the -k or --insecure option to the Curl command. This option explicitly tells Curl to perform "insecure" SSL connections and file transfers. Curl will ignore any security warnings about an invalid SSL certificate and accept it as valid.
If your product supports the HTTPS server feature, you can update a self-signed certificate using Web Config. Access Web Config and select Network Security Settings, select SSL/TLS, and select Certificate. Click Update.
I think I have narrowed this down to a change in the web service that I'm calling. Doh!
The Disable-SslVerification
and Enable-SslVerification
function that I listed in my question are still the best way to go and seem to work.
I look forward to the -SkipCertificateCheck
switch mentioned by Bacon Bits in the comments. Then, we can stop hacking. =)
Hopefully this question is valuable for people who are trying to solve the same problem but run into the An unexpected error occurred on a send
problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With