Powershell 3.0 Invoke-WebRequest HTTPS在所有请求上失败

时间:2014-08-05 16:31:55

标签: rest powershell https powershell-v3.0

我正在尝试通过Powershell 3.0和REST API使用我们的Load Balancer。但是,无论我尝试什么,如果它是https请求,无论是我们的负载均衡器还是任何其他https站点,我目前都会遇到故障。我觉得我错过了一些明显的东西。

以下是使用https

失败的代码
try
{
    #fails
    #$location='https://www.bing.com'
    #fails
    #$location='https://www.google.com'
    #fails
    #$location='https://www.facebook.com'
    #fails
    #$location='https://www.ebay.com'
    #works
    #$location='http://www.bing.com'
    #works
    #$location='http://www.google.com'
    #fails (looks like Facebook does a redirect to https://)
    $location='http://www.facebook.com'
    #works
    #$location='http://www.ebay.com'
    $response=''
    $response = Invoke-WebRequest -URI $location
    $response.StatusCode
    $response.Headers
}
catch
{
    Write-Host StatusCode $response.StatusCode
    Write-Host $_.Exception
}

我得到的错误是:

System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.Management.Automation.PSInvalidOperationException: 
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.Runspa
ce type. The script block you attempted to invoke was: $true
   at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
   at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
   --- End of inner exception stack trace ---
   at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetResponse(WebRequest request)
   at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()

我希望this page和底部的建议,包括来自Aaron D.的建议会有所作为,但没有一个能有所作为。

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

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
}

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

我尝试过切换到Invoke-RestCommand,但无效,因为我得到相同的响应。

感觉这必须是环境因素,因为我无法相信上述内容对其他人不起作用,但我已经在工作站和服务器上尝试了相同的结果(不规则)彻底摆脱环境,但我知道它们的设置不同。)

有什么想法吗?

5 个答案:

答案 0 :(得分:30)

这对我来说非常合适。该网站默认为TLS 1.0,显然PS不适用于此。我用过这一行:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

我的PS脚本(到目前为止我测试过的所有内容)都运行得很好。

答案 1 :(得分:20)

答案是不要这样做来解决SSL问题:

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

如果你这样做,你的第一个https请求将起作用(似乎),但后续的请求不会。此外,你需要关闭Powershell ISE,然后重新打开它,然后再试一次(没有那条线)。

这是在http://social.technet.microsoft.com/Forums/windowsserver/en-US/79958c6e-4763-4bd7-8b23-2c8dc5457131/sample-code-required-for-invokerestmethod-using-https-and-basic-authorisation?forum=winserverpowershell - &#34;这句话中提到的;并且所有后续运行都会产生此错误:&#34;,但它不清楚重置的解决方案是什么。< / p>

答案 2 :(得分:6)

我也被这个困扰了很长一段时间。它甚至影响了Visual Studio,因为VS在运行NuGet还原时将$PROFILE加载到了它的域中。

看到上面的评论让我意识到我有一个自定义回调脚本,因为我们的某个供应商在其中发布了带有无效CN的产品的ssl证书。

长话短说,我用已编译的c#对象替换了我的脚本委托(从等式中删除了脚本运行空间)。

(C#突出显示的单独代码块)

using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public static class CustomCertificateValidationCallback {
    public static void Install() 
    {
        ServicePointManager.ServerCertificateValidationCallback += CustomCertificateValidationCallback.CheckValidationResult;
    }

    public static bool CheckValidationResult(
        object sender, 
        X509Certificate certificate, 
        X509Chain chain, 
        SslPolicyErrors sslPolicyErrors)
    {
        // please don't do this. do some real validation with explicit exceptions.
        return true;
    }
}

在Powershell中:

Add-Type "" # C# Code
[CustomCertificateValidationCallback]::Install()

答案 3 :(得分:0)

为了巩固和总结上述一些知识,我采用了以下方法:

语法的颜色和注释类似于以前的C#:

// Piggyback in System.Net namespace to avoid using statement(s)
namespace System.Net 
{
    // Static class to make the ps call easy
    // Uses a short name that is unlikely to clash with real stuff...YMMV
    public static class Util 
    {
        // Static method for a static class
        public static void Init() 
        {
            // [optionally] clear any cruft loaded into this static scope
            ServicePointManager.ServerCertificateValidationCallback = null;

            // Append a dangerously permissive validation callback
            // using lambda syntax for brevity.
            ServicePointManager.ServerCertificateValidationCallback += 
                (sender, cert, chain, errs) => true;

            // Tell SPM to try protocols that have a chance 
            // of working against modern servers.
            // Word on the street is that these will be tried from "most secure" 
            // to least secure. Some people add em all!
            ServicePointManager.SecurityProtocol = 
                SecurityProtocolType.Tls | 
                SecurityProtocolType.Tls11 | 
                SecurityProtocolType.Tls12;
        }
    }
}

现在是真正的Powershell高亮版本(没有注释,但代码相同)

Add-Type -Language CSharp @"
namespace System.Net {
public static class Util {
public static void Init() {
ServicePointManager.ServerCertificateValidationCallback = null;
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, errs) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
}}}"@
[System.Net.Util]::Init()

很明显,您可以删除不相关的空格,但是应该可以将其删除到会话中,然后随意Invoke-WebRequest

请注意

# Do not use IMHO!
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

方法对于ps 5.1似乎很不正确(我已经在其中进行了测试)。不知道它来自哪里,但我希望我避免了它并挽救了心痛。

答案 4 :(得分:0)

下面的powershell脚本可帮助我检查发布的Web请求

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

$uri = "XXXX"
$person = @{grant_type= 'user_password'
username = 'XXXX'
password = 'XXX'
}
   $body = (ConvertTo-Json $person)
   $hdrs = @{}
   $hdrs.Add("XXXX","XXXX")


Invoke-RestMethod -Uri $uri -Method Post -Body $body -ContentType 'application/json' -Headers $hdrs