Powershell 3.0 Invoke-WebRequest HTTPS завершает работу по всем запросам

Я пытаюсь работать с нашим балансировщиком нагрузки через 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()

Я надеялся эту страницу и предложения на дно, в том числе и от Аарона Д.), будет иметь значение, но ни один из них не изменил ситуацию.

[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
    [email protected]'
    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, но безрезультатно, поскольку получаю тот же ответ.

Похоже, что это должно быть чем-то экологичным, потому что я не могу поверить, что это не работает ни для кого другого, но я пробовал его на рабочей станции и на сервере с теми же результатами (не правило но я знаю, что они были настроены по-разному).

Любые мысли?

Ответ 1

Это отлично сработало для меня. Сайт по умолчанию использует TLS 1.0, и, по-видимому, PS не работает с этим. Я использовал эту строку:

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

Мои сценарии PS (пока все, что я тестировал) отлично работали.

Ответ 2

Ответ на этот вопрос не позволяет решить проблему SSL:

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

Если вы это сделаете, ваш первый запрос https будет работать (кажется), однако последующих не будет. Кроме того, в этот момент вам нужно закрыть ISE Powershell и снова открыть его, а затем повторить попытку (без этой строки).

Об этом говорится в приведенном здесь предложении 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 - "И все последующие прогоны порождают эту ошибку:", но было неясно, какое решение reset был.

Ответ 3

Я тоже очень долго страдал от этого. Это даже повлияло на Visual Studio, поскольку VS загрузил мой $PROFILE в его домен при запуске восстановления NuGet.

Увидев ваш комментарий выше, я понял, что у меня был пользовательский callback script, потому что один из наших поставщиков отправил продукт с недопустимым CN в ssl cert.

Короче говоря, я заменил делегата script на скомпилированный объект С# (удалив пробел script из уравнения).

(отдельный блок кода для выделения С#)

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()

Ответ 4

Объединяя и обобщая некоторые из вышеизложенных уроков, я принял следующий подход:

Синтаксис раскрашен и прокомментирован как С# былого:

// 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 (где я проверил это). Не уверен, откуда это взялось, но я бы хотел избежать этого и спасти душевную боль.