web-dev-qa-db-ja.com

Powershell 3.0 Invoke-WebRequest HTTPSがすべてのリクエストで失敗する

Powershell 3.0およびREST API。または他の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()

私は このページ と、アーロン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に切り替えてみましたが、同じ応答が返されるため、役に立ちません。

これは他の人にはうまくいかないとは信じられないので、これは環境的なものでなければならないようですが、ワークステーションとサーバーで試してみましたが、同じ結果が得られました(環境を完全に排除していないわけではありません)しかし、私はそれらが異なってセットアップされたことを知っています)。

何かご意見は?

14
mapeterson42

これは私にとっては完璧に機能しました。サイトはデフォルトでTLS 1.0に設定されており、PSは明らかにそれで動作しません。私はこの行を使用しました:

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

私のPSスクリプト(これまでにテストしたすべてのスクリプト)は完全に機能しました。

31
Daniel Peel

答えは、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-authorization?forum = winserverpowershell -「以降のすべての実行でこのエラーが発生します:」しかし、リセットするための解決策が明確ではありませんでした。

20
mapeterson42

私もこれに長い間悩まされていました。 NuGet復元の実行時にVSがドメインにドメイン$PROFILEをロードしたため、Visual Studioにも影響しました。

上記のコメントを見て、ベンダーの1つが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()

以下の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
0
Gautam Sharma

上記の学習のいくつかを統合して凝縮するために、私は次のアプローチを採用しました。

構文は色分けされ、C#of yoreのようにコメント化されています。

// 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(私がこれをテストしたところ)ではかなり間違っているようです。それがどこから来たのかはわかりませんが、私はそれを避けて心の痛みを救ったといいのですが。

0
el2iot2