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

Posted

技术标签:

【中文标题】Powershell 3.0 Invoke-WebRequest HTTPS 在所有请求上都失败【英文标题】:Powershell 3.0 Invoke-WebRequest HTTPS Fails on All Requests 【发布时间】:2014-09-28 10:02:12 【问题描述】:

我正在尝试通过 Powershell 3.0 和 REST API 使用我们的负载均衡器。但是,无论我尝试什么,如果它是一个 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 但无济于事,因为我得到了相同的响应。

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

有什么想法吗?

【问题讨论】:

好的,所以它肯定似乎与配置有关。此Invoke-RestMethod -Uri "https://gdata.youtube.com/feeds/api/videos?v=2&q=PowerShell" 适用于 PSVersion 为 3 0 -1 -1 的 Windows Server 2012 不适用于 PS 版本为 3 0 -1 -1 的 Windows Server 2008 R2 并且也不适用于具有以下版本的 Windows 8.1 4 0 -1 -1 【参考方案1】:

下面的 powershell 脚本适用于我检查发布网络请求

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

【讨论】:

【参考方案2】:

巩固和凝练上面的一些学习,我采用了以下方法:

语法着色和注释就像昔日的 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 *** 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 高亮版本(没有 cmets,但代码相同)

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 来说似乎很不正确(我已经测试过了)。不知道它是从哪里来的,但我希望我能避免它并避免心痛。

【讨论】:

【参考方案3】:

这对我来说非常有效。该站点默认为 TLS 1.0,显然 PS 无法使用它。我用了这条线:

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

我的 PS 脚本(到目前为止我测试过的所有脚本)运行良好。

【讨论】:

@daniel-peel - 这个答案对我有用,但由于链接无效,请您将相关的博客文章文本嵌入到答案中。 @Castrohenge 如果你用谷歌搜索链接,你可以查看页面的缓存版本......这只是另一篇关于某人正在寻找类似内容的博客文章。我试过了……它奏效了……所以我参考了我找到信息的地方。该页面显然不再可用。我不想将整个页面粘贴在这里..因为它很长。我创建了一个页面的 pastebin...从今天开始一个月有效pastebin.com/LQp8hsfq...如果您觉得应该在这里发布...请告诉我【参考方案4】:

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

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

长话短说,我用编译的 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()

【讨论】:

IIS 的自签名证书工作正常【参考方案5】:

答案是不要这样做来解决 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 的一句话中提到了 - “所有后续运行都会产生这个错误:”,但不清楚重置的解决方案是什么。

【讨论】:

这对我在 POSH5、Win10 中不起作用。在设置后的第一次调用(以及所有后续调用)中,我得到:Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send. 将协议显式设置为 TLS 1.2 对我有用:[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 我可以确认。设置[System.Net.ServicePointManager]::ServerCertificateValidationCallback = $true 让我大吃一惊。不推荐。

以上是关于Powershell 3.0 Invoke-WebRequest HTTPS 在所有请求上都失败的主要内容,如果未能解决你的问题,请参考以下文章

基于PowerShell 3.0的web接口测试

如何将Powershell版本从3.0升级到4.0或5.0

批量隐藏 Invoke-WebRequest

Win7中安装Windows PowerShell 3.0

使用 Powershell 3.0 切换 IIS 7.5 身份验证“匿名身份验证”?

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