159

Using Powershell v3's Invoke-WebRequest and Invoke-RestMethod I have succesfully used the POST method to post a json file to a https website.

The command I'm using is

 $cert=New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("cert.crt")
 Invoke-WebRequest -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert -Body $json -ContentType application/json -Method POST

However when I attempt to use the GET method like:

 Invoke-WebRequest -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert -Method GET

The following error is returned

 Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
 At line:8 char:11
 + $output = Invoke-RestMethod -Uri https://IPADDRESS/resource -Credential $cred
 +           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest)      [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

I have attempted using the following code to ignore SSL cert, but I'm not sure if its actually doing anything.

 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

What might be going wrong here and how to fix it?

3
  • So which one are you using? Invoke-RestMethod or Invoke-WebRequest? Commented Jul 30, 2012 at 15:35
  • Invoke-WebRequest. I use it as it returns the request/resposne headers unlike Invoke-RestMethod. However I have tried Invoke-RestMethod which takes identical parameters as well. Commented Jul 30, 2012 at 18:47
  • For what it's worth, the ServerValidationCallback thing is almost certainly a red herring, since the error you should get when you have an SSL validation problem shoudl SAY that: Invoke-WebRequest : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. You could try exploring $Error[0].Exception.InnerException for more information... Commented Sep 21, 2012 at 19:39

12 Answers 12

218

This work-around worked for me: http://connect.microsoft.com/PowerShell/feedback/details/419466/new-webserviceproxy-needs-force-parameter-to-ignore-ssl-errors

Basically, in your PowerShell script:

add-type @"
    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;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

$result = Invoke-WebRequest -Uri "https://IpAddress/resource"
Sign up to request clarification or add additional context in comments.

6 Comments

Note, this answer is correct; however, the point made on another answer (stackoverflow.com/a/25163476/68432) is also valid. This solution won't work if you've done "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}" beforehand.
You need to add the Type condition check as per Arthur Strutzenberg answer below or you will get an error saying the type already exists
5 years later, that's still the solution for PowerShell 5.1 (full .NET Framework). For PowerShell Core there's a -SkipCertificateCheck now.
MS have taken down Connect, that link is invalid. Is there another link?
@Amjad There is indeed a security risk using this in production - If somebody redirects your call to a malicious alternative endpoint (could be as simple as editing the hosts file on the machine calling it) then your call will be made regardless sending all info to the attacker
|
98

Lee's answer is great, but I also had issues with which protocols the web server supported.
After also adding the following lines, I could get the https request through. As pointed out in this answer https://stackoverflow.com/a/36266735

$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols

My full solution with Lee's code.

add-type @"
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;
    }
}
"@
$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

10 Comments

have you found better solution, coz if you have 40 scripts then you have to add it to each?. Seems not making any sense. Btw, thank for the answer
Lee's answer didn't work for me. I had to add the bits you referenced and IT WORKED!
Thank you thank you thank your showing me the SecurityProtocol global static property. Christ, I've just lost DAYS on checking certificates, trusts, network, routes, permissions, and shitload of other things trying to solve vague endpoint does not respond error when accessing one specific server via https (all other do work), just because that goddamn powershell 5.1 defaults to SSL3,TLS and it JUST BLOCKS GODDAMN TLS11 and TLS12 BY DEFAULT god how much I hate this crap I should have written that script in C#/Ruby/C++, or whatever else that is not powershell
@quetzalcoatl, how to change the defaults? Yours and AndOs helped me a lot, this sufficed: $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12' and then [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
@StanTastic: I think it's impossible to permanently change the defaults. I think it's hardcoded in the ServicePointManager source code. I never checked though, so maybe there is some way.
|
22

An alternative implementation in pure (without Add-Type of source):

#requires -Version 5
#requires -PSEdition Desktop

class TrustAllCertsPolicy : System.Net.ICertificatePolicy {
    [bool] CheckValidationResult([System.Net.ServicePoint] $a,
                                 [System.Security.Cryptography.X509Certificates.X509Certificate] $b,
                                 [System.Net.WebRequest] $c,
                                 [int] $d) {
        return $true
    }
}
[System.Net.ServicePointManager]::CertificatePolicy = [TrustAllCertsPolicy]::new()

Comments

15

Invoke-WebRequest "DomainName" -SkipCertificateCheck

You can use -SkipCertificateCheck Parameter to achieve this as a one-liner command ( THIS PARAMETER IS ONLY SUPPORTED ON CORE PSEDITION )

2 Comments

This parameters saved me. I use invoke-WebRequest in Azure and it doesn't support "Add-Type", only this can work. Thank you very much!
I've installed PSCoreEdition (7.x) on Windows 2012 machine, run Invoke-WebRequest -Uri "10.2.177.125/hp/device/InternalPages/Index?id=UsagePage" -SkipCertificateCheck -Method GET and got the following error Invoke-WebRequest : Cannot find a parameter matching parameter name 'SkipCertificateCheck'. Also, can not find any references to this parameter online. Would someone comment?
11

Did you try using System.Net.WebClient?

$url = 'https://IPADDRESS/resource'
$wc = New-Object System.Net.WebClient
$wc.Credentials = New-Object System.Net.NetworkCredential("username","password")
$wc.DownloadString($url)

6 Comments

Sunny, I receive the following when using that code: Exception calling "DownloadString" with "1" argument(s): "The remote server returned an error: (406) Not Acceptable." At line:4 char:1 + $wc.DownloadString($url) + ~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : WebException
Based on the API documentation of the REST service im using 406 indicates "that the accept header included in the request does not allow an XML or JSON response"
What response types are allowed if XML / JSON responses are not allowed ?
Is this a custom web service you are using ? Is there any publicly available documentation for the REST API ?
It is a ticketing system called EM7 I dont believe they have public docs. The service does accept JSON/XML response (works just fine if I use cURL) I believe the error is indicating that System.Net.WebClient isnt?
|
8

The following worked worked for me (and uses the latest non deprecated means to interact with the SSL Certs/callback functionality), and doesn't attempt to load the same code multiple times within the same powershell session:

if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type)
{
$certCallback=@"
    using System;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    public class ServerCertificateValidationCallback
    {
        public static void Ignore()
        {
            if(ServicePointManager.ServerCertificateValidationCallback ==null)
            {
                ServicePointManager.ServerCertificateValidationCallback += 
                    delegate
                    (
                        Object obj, 
                        X509Certificate certificate, 
                        X509Chain chain, 
                        SslPolicyErrors errors
                    )
                    {
                        return true;
                    };
            }
        }
    }
"@
    Add-Type $certCallback
 }
[ServerCertificateValidationCallback]::Ignore();

This was adapted from the following article https://d-fens.ch/2013/12/20/nobrainer-ssl-connection-error-when-using-powershell/

Comments

5

I found that when I used the this callback function to ignore SSL certificates [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

I always got the error message Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send. which sounds like the results you are having.

I found this forum post which lead me to the function below. I run this once inside the scope of my other code and it works for me.

function Ignore-SSLCertificates
{
    $Provider = New-Object Microsoft.CSharp.CSharpCodeProvider
    $Compiler = $Provider.CreateCompiler()
    $Params = New-Object System.CodeDom.Compiler.CompilerParameters
    $Params.GenerateExecutable = $false
    $Params.GenerateInMemory = $true
    $Params.IncludeDebugInformation = $false
    $Params.ReferencedAssemblies.Add("System.DLL") > $null
    $TASource=@'
        namespace Local.ToolkitExtensions.Net.CertificatePolicy
        {
            public class TrustAll : System.Net.ICertificatePolicy
            {
                public bool CheckValidationResult(System.Net.ServicePoint sp,System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Net.WebRequest req, int problem)
                {
                    return true;
                }
            }
        }
'@ 
    $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
    $TAAssembly=$TAResults.CompiledAssembly
    ## We create an instance of TrustAll and attach it to the ServicePointManager
    $TrustAll = $TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
    [System.Net.ServicePointManager]::CertificatePolicy = $TrustAll
}

Comments

1

I tried searching for documentation on the EM7 OpenSource REST API. No luck so far.

http://blog.sciencelogic.com/sciencelogic-em7-the-next-generation/05/2011

There's a lot of talk about OpenSource REST API, but no link to the actual API or any documentation. Maybe I was impatient.

Here are few things you can try out

$a = Invoke-RestMethod -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert 
$a.Results | ConvertFrom-Json

Try this to see if you can filter out the columns that you are getting from the API

$a.Results | ft

or, you can try using this also

$b = Invoke-WebRequest -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert 
$b.Content | ConvertFrom-Json

Curl Style Headers

$b.Headers

I tested the IRM / IWR with the twitter JSON api.

$a = Invoke-RestMethod http://search.twitter.com/search.json?q=PowerShell 

1 Comment

Thank you for all your assistance. However the first command $a = Invoke-RestMethod (...) is the one which does not currently work for me. Works fine for a HTTP site but when you introduce HTTPS which EM7 does it returns the error described. That is for Invoke-RestMethod and Invoke-WebRequest. I am in the process of just using an Invoke-Command cmdlet and running curl.
0

These registry settings affect .NET Framework 4+ and therefore PowerShell. Set them and restart any PowerShell sessions to use latest TLS, no reboot needed.

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord 

See https://learn.microsoft.com/en-us/dotnet/framework/network-programming/tls#schusestrongcrypto

1 Comment

For anyone else seeing this answer, our experience is that this registry patch does, in fact, require a reboot to guarantee proper functionality. When trying to ensure a TLS 1.2 connection between a Windows box running a .NET app, SSL 3 was shown via network trace to be used with this registry value in place, but before a reboot; TLS 1.2 was invoked only after a reboot.
0

Using a vpn and changing your location from there works completely fine. I wasn't able to access raw.githubusercontent.com as in my country, my isp has blocked that url, I tried using a vpn and now it works very well.

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
0

I imagine (for PS v5.1) this might do the trick too:

Add-Type -TypeDefinition @"
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public static class CertValidationOverride
{
    public static void Enable()
    {
        ServicePointManager.ServerCertificateValidationCallback +=
            delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                return true;
            };
    }
}
"@

[CertValidationOverride]::Enable()

Comments

-1
  1. Run this command

New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname {your-site-hostname}

in powershell using admin rights, This will generate all certificates in Personal directory

  1. To get rid of Privacy error, select these certificates, right click → Copy. And paste in Trusted Root Certification Authority/Certificates.
  2. Last step is to select correct bindings in IIS. Go to IIS website, select Bindings, Select SNI checkbox and set the individual certificates for each website.

Make sure website hostname and certificate dns-name should exactly match

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.