Search code examples
powershellsslhttpwebrequesttls1.2servicepointmanager

PowerShell Invoke-WebRequest throws WebCmdletResponseException


When executing the line Invoke-WebRequest -Uri https://www.freehaven.net/anonbib/date.html PowerShell throws WebCmdletResponseException. How can I get more information about it, and what may be causing this? While I can successfully get the contents of the page using Python, but in PowerShell it throws an exception.

Full exception:

Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send.
At line:1 char:1
+ Invoke-WebRequest -Uri https://www.freehaven.net/anonbib/date.html
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebExc
   eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

Solution

  • This is because Invoke-WebRequest uses HttpWebRequest under the hood, which in all but the most recent versions of .Net defaults to using SSLv3 and TLSv1.

    You can see this by looking at the current value:

    [System.Net.ServicePointManager]::SecurityProtocol
    

    The site you're connecting to only supports TLS 1.2.

    You can change the allowed protocols, but it applies globally during your application's run:

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

    This overwrites the value.

    Of course that would break anything else in your application which relies on a connection to a server that doesn't support TLS 1.2

    A safe method might be to add TLS 1.2:

    [System.Net.ServicePointManager]::SecurityProtocol = (
        [System.Net.ServicePointManager]::SecurityProtocol -bor 
        [System.Net.SecurityProtocolType]::Tls12
    )
    
    # parentheses are for readability
    

    On the off-chance this still causes a problem for other sites (not sure what, maybe a site that says it accepts TLS 1.2 but its implementation is broken while its TLS 1.0 works fine?), you can save the previous value and restore it.

    $cur = [System.Net.ServicePointManager]::SecurityProtocol]
    try {
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
        Invoke-WebRequest -Uri https://www.freehaven.net/anonbib/date.html
    } finally {
        [System.Net.ServicePointManager]::SecurityProtocol = $cur
    }