在使用 PowerShell 执行 Invoke-WebRequest 或 Invoke-RestMethod(以及它们的别名 iwr 和 irm)下载或请求 HTTPS 资源时,经常遇到以下错误:
irm : 基础连接已经关闭:发送时发送错误。
(The underlying connection was closed: An error occurred while sending.)这个错误通常由 TLS/SSL 协议版本不匹配 引起,尤其是在较旧的 Windows 版本或未安装更新的 PowerShell 环境中。
本文将深入分析问题原因,并提供三种有效的解决方案。
错误原因分析
什么是 TLS?
TLS(Transport Layer Security,传输层安全协议)是 HTTPS 连接的基础安全协议。它的主要版本包括:
| 协议版本 | 发布年份 | 安全状态 | 当前使用 |
|---|---|---|---|
| SSL 2.0 | 1995 | ❌ 极不安全 | 已弃用 |
| SSL 3.0 | 1996 | ❌ 不安全(POODLE漏洞) | 已禁用 |
| TLS 1.0 | 1999 | ⚠️ 不够安全 | 大部分现代网站已禁用 |
| TLS 1.1 | 2006 | ⚠️ 不够安全 | 逐渐被禁用 |
| TLS 1.2 | 2008 | ✅ 安全 | 当前标准 |
| TLS 1.3 | 2018 | ✅ 最安全 | 最新标准 |
问题根源
当你使用 PowerShell 的 irm 命令连接某个 HTTPS 服务器时:
- PowerShell 会使用系统默认的 TLS 协议版本发起连接
- 如果目标服务器要求使用 TLS 1.2 或更高版本
- 而你的系统默认只启用了 TLS 1.0/1.1
- 或者仅启用了 SSL 3.0
- 连接将被服务器拒绝,抛出"基础连接已经关闭"错误
常见触发场景:
- 使用
irm下载 GitHub 上的脚本(如irm get.scoop.sh) - 调用 REST API 接口
- 通过 PowerShell 下载文件
- 在 Windows 7 / Server 2012 等旧系统上运行脚本
- 未安装 .NET Framework 更新的系统
错误信息原文:
Invoke-WebRequest : 基础连接已经关闭:发送时发生错误。
The underlying connection was closed: An error occurred while sending.
Invoke-RestMethod : 基础连接已经关闭:接收时发生错误。
The underlying connection was closed: An error occurred while receiving.方法一:在 PowerShell 中指定 TLS 版本(推荐)
在脚本文本执行 irm 之前,添加以下代码强制使用 TLS 1.2:
PowerShell 5.0/5.1
在脚本开头添加:
# 强制使用 TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12然后正常执行 irm:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
irm https://example.com/script.ps1同时启用多个 TLS 版本
# 同时启用 TLS 1.0、1.1、1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls,
[Net.SecurityProtocolType]::Tls11,
[Net.SecurityProtocolType]::Tls12使用位运算(更简洁)
# 启用 TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12PowerShell 7.x
PowerShell 7 默认支持 TLS 1.2 和 1.3,但仍然可以手动指定:
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13添加到 $PROFILE(永久生效)
如果你希望每次打开 PowerShell 时都自动启用 TLS 1.2,可以将其添加到 PowerShell 配置文件中:
# 查看 $PROFILE 路径
$PROFILE
# 如果不存在,创建配置文件
if (!(Test-Path $PROFILE)) {
New-Item -Path $PROFILE -ItemType File -Force
}
# 用记事本打开编辑
notepad $PROFILE在文件中添加以下内容:
# 启用 TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12保存后,重启 PowerShell 即可永久生效。
方法二:使用 curl 替代 irm
如果 PowerShell 的 TLS 设置无法解决,可以改用 Windows 自带的 curl.exe(注意不是 PowerShell 中的 curl 别名)。
在 PowerShell 中使用 curl.exe
curl.exe -L -o output.ps1 https://example.com/script.ps1curl 常用参数说明
| 参数 | 说明 | 示例 |
|---|---|---|
-L |
跟随重定向 | -L |
-o |
输出到文件 | -o file.txt |
-O |
使用远程文件名保存 | -O |
-k |
跳过 SSL 证书验证 | -k |
-s |
静默模式(不显示进度) | -s |
--tlsv1.2 |
强制使用 TLS 1.2 | --tlsv1.2 |
-H |
添加请求头 | -H "Authorization: Bearer ..." |
使用 curl 配合 TLS 1.2 下载脚本
curl.exe --tlsv1.2 -L -O https://raw.githubusercontent.com/example/script.ps1使用 curl 替代 irm 执行远程脚本
传统 irm + iex(Invoke-Expression)模式:
# 旧方式(可能报错)
iex (irm https://example.com/install.ps1)
# 新方式(使用 curl)
iex (curl.exe --tlsv1.2 -sL https://example.com/install.ps1)使用 wget 替代(如果有)
一些 Windows 系统也内置了 wget:
wget --secure-protocol=TLSv1_2 -O output.ps1 https://example.com/script.ps1方法三:通过注册表全局启用 TLS 1.2
如果想在系统层面永久启用 TLS 1.2,可以修改注册表。
适用于 PowerShell 和 .NET Framework
以下注册表设置会强制所有 .NET 和 PowerShell 应用程序使用 TLS 1.2:
-
按
Win + R,输入regedit,回车打开注册表编辑器 -
导航到以下路径:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319-
在右侧空白处右键,新建 "DWORD (32位)值"(即使系统是 64 位也创建 32 位 DWORD)
-
创建以下两个键值:
| 键名 | 数值数据 | 说明 |
|---|---|---|
SystemDefaultTlsVersions |
1 | 使用系统默认 TLS 版本 |
SchUseStrongCrypto |
1 | 使用强加密算法,禁用 SSL 3.0 和 TLS 1.0 |
- 同样的设置应用到 32 位应用程序路径:
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319-
同样创建:
SystemDefaultTlsVersions= 1SchUseStrongCrypto= 1
-
对于 .NET Framework 2.0/3.5,重复上述步骤在以下路径:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v2.0.50727
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v2.0.50727- 关闭注册表编辑器,重启电脑
使用注册表脚本一键导入
将以下内容保存为 enable-tls12.reg 文件,双击导入:
Windows Registry Editor Version 5.00
; .NET 4.x 64位
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001
; .NET 4.x 32位
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001
; .NET 2.0/3.5 64位
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v2.0.50727]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001
; .NET 2.0/3.5 32位
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v2.0.50727]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001更新 .NET Framework 版本
如果上述注册表修改无效,可能需要更新 .NET Framework:
-
下载安装最新版 .NET Framework 4.8:
https://dotnet.microsoft.com/download/dotnet-framework -
Windows Server 2012/2012 R2 需要安装 KB3140245 更新:
从 Microsoft 更新目录下载并安装
PowerShell 版本与 TLS 支持对照表
| PowerShell 版本 | 默认 TLS 版本 | 手动设置 TLS 1.2 |
|---|---|---|
| PowerShell 2.0 | SSL 3.0 / TLS 1.0 | ❌ 不支持 |
| PowerShell 3.0 | SSL 3.0 / TLS 1.0 | ✅ 可行 |
| PowerShell 4.0 | SSL 3.0 / TLS 1.0 | ✅ 可行 |
| PowerShell 5.0 | TLS 1.0 / 1.1 | ✅ 可行 |
| PowerShell 5.1 | TLS 1.0 / 1.1 / 1.2 | ✅ 原生支持 |
| PowerShell 7.x | TLS 1.2 / 1.3 | ✅ 原生支持 |
如果你的 PowerShell 版本低于 5.1,建议更新到最新版本:
# 查看当前版本
$PSVersionTable.PSVersion下载地址:https://aka.ms/powershell-release
常见错误状态与解决方案
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
| "基础连接已经关闭:发送时发送错误" | TLS 版本不匹配 | 指定 TLS 1.2 |
| "基础连接已经关闭:接收时发生错误" | 服务器返回异常 | 检查 URL 是否有效 |
| "未能创建 SSL/TLS 安全通道" | 证书验证失败 | 使用 -SkipCertificateCheck |
| "请求被中止:未能创建 SSL/TLS 安全通道" | 协议版本不支持 | 更新 .NET Framework |
| "无法连接到远程服务器" | 网络不通 | 检查网络连接和防火墙 |
总结
解决 PowerShell irm 报错"基础连接已经关闭"的问题,推荐以下步骤:
快速修复(临时)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
irm https://example.com/script.ps1永久修复
- 将上述命令添加到
$PROFILE - 或者通过注册表全局启用 TLS 1.2
- 或者安装最新版 PowerShell
替代方案
如果 PowerShell 修复无效,直接使用 curl.exe 替代。
建议:对于 Windows 7/8/Server 2012 等旧系统,推荐方法三(注册表全局启用),一劳永逸。对于 Windows 10/11,大多数情况下方法一就足够了。