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:
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:
[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:
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:
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.
