Fixing “Could not create SSL/TLS secure channel” in PowerShell

I ran into one of those frustrating issues that looks simple on the surface, but takes a bit of digging to fully understand.

It started with a PowerShell script.

A straightforward Invoke-WebRequest call.

Nothing fancy.

And then this showed up:

powershell
Invoke-WebRequest : The request was aborted: Could not create SSL/TLS secure channel.

At first glance, it felt like a network issue.

Maybe the endpoint was down.

Maybe a firewall rule.

Maybe something intermittent.

Turns out, it was none of that.

What actually happened

The script was trying to connect to a server that enforces modern security standards.

Specifically, TLS 1.2 or higher.

But the environment I was running the script in?

It was still defaulting to older protocols like TLS 1.0 or SSL 3.0.

And modern servers simply reject those.

So the connection never even got established.

Hence the “secure channel” error.

What I tried first

The quickest way to validate the issue was to explicitly enable newer protocols in the current PowerShell session.

I added this before making the request:

powershell
[Net.ServicePointManager]::SecurityProtocol =
  [Net.SecurityProtocolType]::Tls11 -bor
  [Net.SecurityProtocolType]::Tls12 -bor
  [Net.SecurityProtocolType]::Tls -bor
  [Net.SecurityProtocolType]::Ssl3

And just like that, the request started working.

That confirmed the root cause.

But there was a problem.

This fix is temporary.

Every new PowerShell session would require the same line again.

Not ideal.

The real reason

This behaviour comes from how .NET Framework handles security protocols by default.

Older versions of .NET:

  • Do not automatically use the latest TLS versions
  • Require explicit configuration to opt into stronger cryptography

So even if your OS supports TLS 1.2, your application might not use it unless configured.

That’s exactly what was happening here.

The proper fix

To make this work consistently across all sessions and applications, the fix needs to be applied at the system level.

That means updating the registry so .NET defaults to strong cryptography.

Here’s what I did.

Opened PowerShell as Administrator and ran:

powershell
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" -Name "SchUseStrongCrypto" -Value 1 -Type DWord
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" -Name "SystemDefaultTlsVersions" -Value 1 -Type DWord

And for 64-bit systems:

powershell
Set-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319" -Name "SchUseStrongCrypto" -Value 1 -Type DWord
Set-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319" -Name "SystemDefaultTlsVersions" -Value 1 -Type DWord

Then a restart.

That’s it.

Why this works

These registry keys do two important things:

  • SchUseStrongCrypto → Forces .NET to prefer modern, secure protocols like TLS 1.2
  • SystemDefaultTlsVersions → Lets the OS decide the best available TLS version

In short, you stop hardcoding old behaviour and let the system use secure defaults.

Bonus: A better long-term approach

If you’re still using Windows PowerShell (5.1 or older), you’re more likely to hit issues like this.

Switching to PowerShell 7+ helps a lot.

It uses modern .NET under the hood and defaults to secure protocols out of the box.

Less configuration.

Fewer surprises.

Final thoughts

This issue looks like a connectivity problem.

But it’s really a protocol mismatch.

And it’s a good reminder of something we often overlook:

Secure defaults matter.

Especially when older runtimes are involved.

If your scripts suddenly start failing against newer APIs, don’t just check the endpoint.

Check what your client is negotiating under the hood.

It might just be stuck in the past.