151

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?

desertnaut
  • 57,590
  • 26
  • 140
  • 166
floyd
  • 2,080
  • 4
  • 17
  • 19
  • So which one are you using? `Invoke-RestMethod` or `Invoke-WebRequest`? – svick Jul 30 '12 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. – floyd Jul 30 '12 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... – Jaykul Sep 21 '12 at 19:39

11 Answers11

211

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"
Lee Grissom
  • 9,705
  • 6
  • 37
  • 47
  • 11
    Note, this answer is correct; however, the point made on another answer (http://stackoverflow.com/a/25163476/68432) is also valid. This solution won't work if you've done "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}" beforehand. – Paul Suart Sep 27 '15 at 21:54
  • 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 – Ralph Willgoss Feb 06 '18 at 15:57
  • Is there a security risk for using this in production? – Amjad Mar 22 '18 at 12:15
  • 25
    5 years later, that's still the solution for PowerShell 5.1 (full .NET Framework). For PowerShell Core there's a `-SkipCertificateCheck` now. – evilSnobu Apr 14 '18 at 08:27
  • 1
    MS have taken down Connect, that link is invalid. Is there another link? – silicontrip Jul 22 '20 at 04:05
  • 1
    @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 – Dan Harris Nov 15 '20 at 14:48
95

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
AndOs
  • 1,314
  • 9
  • 6
  • 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 – Ender Oct 25 '17 at 10:47
  • 2
    Lee's answer didn't work for me. I had to add the bits you referenced and IT WORKED! – Pat K Nov 03 '17 at 16:42
  • Thank you very much, specifying the protocols helped to solve the problem – Alex Jun 26 '18 at 19:16
  • 2
    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 Jun 29 '18 at 20:06
  • 1
    @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 Oct 04 '18 at 14:03
  • 1
    @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. – quetzalcoatl Oct 04 '18 at 14:56
  • If you don't want to typecast a string to enum, then this is the typesafe way `[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls -bor [System.Net.SecurityProtocolType]::Ssl3; ` – Adarsha Nov 20 '18 at 04:54
  • SSLv3 Padding Oracle Attack Information Disclosure Vulnerability (POODLE) `SOLUTION:` Disable SSLv3 support to avoid this vulnerability. But by default `[System.Net.ServicePointManager]::SecurityProtocol` is `Ssl3, Tls` and Ssl3 just could be disabled in you organization. – it3xl Dec 28 '20 at 18:09
  • @StanTastic , @quetzalcoatl I believe you can change the default TLS version that PowerShell will use; however, this involves a series of changes you have to implement. Basically, install the required updates (update .NET to v4.6.2+, and if on Win7, install KB3140245). Then configure the necessary reg values that will enable TLS 1.2, add it to the `DefaultSecureProtocols` list and tell .NET apps to use the configured OS default protocols. PowerShell being a .NET-based app, will then begin to use the system defaults (i.e. TLS 1.2). – dwillis77 Jun 04 '21 at 00:00
  • When this is properly configured, running `[Net.ServicePointManager]::SecurityProtocol` in PowerShell (without making any changes to it) should return `SystemDefault` as the value. Assuming TLS 1.2 is configured as a system default at that point, you should be good to go. See [here](https://learn.microsoft.com/en-us/mem/configmgr/core/plan-design/security/enable-tls-1-2-client) for more info. – dwillis77 Jun 04 '21 at 00:01
20

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()
Maximilian Burszley
  • 18,243
  • 4
  • 34
  • 63
13

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 )

Amar Helloween
  • 141
  • 1
  • 3
  • 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! – kain Sep 03 '20 at 08:51
  • I've installed PSCoreEdition (7.x) on Windows 2012 machine, run Invoke-WebRequest -Uri "https://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? – NKAT Nov 25 '22 at 11:58
10

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)
Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
  • 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 – floyd Jul 31 '12 at 14:47
  • 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" – floyd Jul 31 '12 at 14:53
  • What response types are allowed if XML / JSON responses are not allowed ? – Sunny Chakraborty Jul 31 '12 at 17:31
  • Is this a custom web service you are using ? Is there any publicly available documentation for the REST API ? – Sunny Chakraborty Jul 31 '12 at 17:31
  • 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? – floyd Jul 31 '12 at 18:35
  • I used this instead of invoke-webrequest to work around a server that was sending back malformed http headers – Pete Jun 25 '15 at 16:34
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/

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
}

Aaron D
  • 5,817
  • 1
  • 36
  • 51
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 
desertnaut
  • 57,590
  • 26
  • 140
  • 166
  • 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. – floyd Aug 02 '12 at 00:47
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

Jeremy Cook
  • 20,840
  • 9
  • 71
  • 77
  • 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. – David W May 08 '19 at 13:02
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.

  • 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](/help/how-to-answer). – Community May 21 '23 at 11:52
-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

Mohit Dharmadhikari
  • 3,750
  • 2
  • 20
  • 27