33

When I try to use Invoke-WebRequest I'm getting some weird error:

Invoke-WebRequest -Uri "https://idp.safenames.com/"

Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send.

I'm not sure what's causing it, as the website itself seems fine.

Even with all the "ignore ssl errors" functions around stackoverflow, it's still not working, making me wonder if it's related to SSL at all.

iTayb
  • 12,373
  • 24
  • 81
  • 135
  • Try setting your user agent to a normal browser with the `-UserAgent` parameter. Maybe the site is blocking connections from "bots". – briantist Mar 28 '16 at 15:40
  • @briantist Thought about it, but no, even with proper useragent this fails. – iTayb Mar 28 '16 at 15:43
  • https://www.codyhosterman.com/2016/06/force-the-invoke-restmethod-powershell-cmdlet-to-use-tls-1-2/, https://www.entrustdatacard.com/blog/2011/may/is-it-ssl-tls-or-https – firstpostcommenter Jun 29 '18 at 12:11

4 Answers4

68

As BaconBits notes, .NET version > 4.5 uses SSLv3 and TLS 1.0 by default.

You can change this behavior by setting the SecurityProtocol policy with the ServicePointManager class:

PS C:\> $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
PS C:\> [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
PS C:\> (Invoke-WebRequest -Uri "https://idp.safenames.com/").StatusCode
200

This will apply to all requests in the AppDomain (so it only applies to the current instance of the host application).


There's a module on GitHub and in PSGallery that can manage these settings now:

Install-Module BetterTls -Scope CurrentUser
Import-Module BetterTls
Enable-Tls -Tls11 -Tls12
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • What am I doing wrong? I seriously can't tell... http://imgur.com/FgHqF1o – kayleeFrye_onDeck Nov 12 '16 at 07:32
  • Powershell 4.0 or 4 0 -1 -1 when using the psversiontable.psversion query – kayleeFrye_onDeck Nov 12 '16 at 07:36
  • Behavior repro on 2 diff windows boxes, win8.1 & 10 – kayleeFrye_onDeck Nov 12 '16 at 07:41
  • How do we *know* that it was caused by an error during TLS negotiation? I had this situation and could not, for the life of me, get anything out of the WebException that said anything about TLS. The problem appeared only during automated tests, not during manual tests. How, on the client side, could I get a message that says "the client tried to negotiate with TLS 1.0 and the server rejected it." Or SOME kind of pseudo-English explanation for the error, beyond "An unexpected error occurred on a send." Also why does my interactive PS shell use TLS1.2 while a new powershell.exe uses TLS1.0 ? – Cheeso Nov 13 '17 at 19:01
  • 1
    @Cheeso - the best thing you can do (or more accurately, the only thing) is to enable SChannel debugging as per https://support.microsoft.com/en-us/help/260729/how-to-enable-schannel-event-logging-in-iis ... annoyingly, this usually needs a reboot to actually take effect. SChannel is the windows subsystem dedicated to SSL/TLS connection and session management, so anything using the Windows APIs for SSL/TLS connections will go through it. Log events go into the windows event viewer logs. Should work for clients as well as servers. – Chris J Apr 14 '18 at 23:00
  • 1
    Setting accepted TLS versions on application code goes [against best practices recommended by Microsoft](https://learn.microsoft.com/en-us/dotnet/framework/network-programming/tls). [TLS 1.0 and 1.1 are deprecated](https://learn.microsoft.com/en-us/lifecycle/announcements/transport-layer-security-1x-disablement). An application that uses will fail again if TLS 1.2 is deprecated as well. – Monticola Explorator Oct 25 '21 at 11:10
16

This can be permanently changed as well

# set strong cryptography on 32 bit .Net Framework (version 4 and above)
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
# set strong cryptography on 64 bit .Net Framework (version 4 and above)
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord 
Jay
  • 161
  • 1
  • 2
  • More info at [Transport Layer Security (TLS) best practices with the .NET Framework - Configuring security via the registry](https://learn.microsoft.com/en-us/dotnet/framework/network-programming/tls#configuring-security-via-the-windows-registry). – mklement0 Jun 24 '23 at 18:02
12

Based on this scan, it doesn't look like that URI supports anything lower than TLS 1.1.

What version of Windows are you on? If you're on PowerShell v4.0 or lower, you're not going to be able to negotiate a TLS 1.1 or 1.2 connection because the .Net Framework doesn't support TLS 1.1 or 1.2 until .Net Framework 4.5. PowerShell v4.0 is .Net 4.0. That means the underlying System.Net.WebRequest classes can't negotiate a connection. I believe PowerShell v5.0 is .Net 4.5 or .Net 4.6, but I don't have a Win 10 client to check the $PSVersionTable right now.

You may be able to get it to work by coding the calls to WebRequest manually and specifying the protocol as [System.Net.SecurityProtocolType]::Tls12 or [System.Net.SecurityProtocolType]::Tls11, but I'm not sure if that's possible. That's supposed to work if .Net 4.5 is installed from what I'm seeing, but, again, I've never tried it.

For reference, I get the exact same results as you on Windows 7 x64/Powershell v4.0 and I've got .Net 4.5 installed, but I've never tried manually coding the WebRequest. I also get an error if I use wget for Windows 1.11.4 from here (OpenSSL 0.9.8b, well before TLS 1.1 and 1.2), but it works just fine if I use wget for Windows 1.17.1 from here (current, more or less).

Bacon Bits
  • 30,782
  • 5
  • 59
  • 66
  • Helpful, but.... The original question said `I'm not sure what's causing it` Teach a person to fish.... How do we *know* that it's a TLS problem? I had this situation and could not, for the life of me, get anything out of the WebException that said "error during TLS negotiation". Worse, the problem appeared only during automated tests, not manual tests. How, on the client side, could I get a message that says "the client tried to negotiate with TLS 1.0 and the server rejected it." Or SOME kind of pseudo-English explanation for the error, beyond "An unexpected error occurred on a send." – Cheeso Nov 13 '17 at 18:55
  • @Cheeso You're often not going to get a helpful error here at all because the server doesn't return an error to the client. It just terminates the connection. All the client knows is that the connection ended or was refused. You'd need to watch the communication with Wireshark, which isn't fun with TLS. – Bacon Bits Nov 14 '17 at 15:13
4

One line:

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

Oleh Tarasenko
  • 601
  • 5
  • 17
  • This answer repeats (some) information available in much earlier answers, but does not include any explanation. Nor is the code actually much simpler. – Nathan Tuggy Feb 19 '22 at 23:53
  • 1
    This should have been the accepted answer – Fandango68 Aug 25 '22 at 06:41
  • The one-liner that corresponds to the accepted answer is: `[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType] 'Ssl3, Tls, Tls11, Tls12'` (at least in v5.1 you don't even need the `[System.Net.SecurityProtocolType]` cast); recent .NET versions additionally support `Tls13` – mklement0 Jun 24 '23 at 17:27