# Could not create SSL/TLS secure channel：PowerShell 修法

> Windows PowerShell 和 .NET Framework 没能和服务器协商出 TLS，多半是没有启用 TLS 1.2。按微软推荐的方式开启它，跳过证书检查没有用。

Source: https://ssl.sh/zh/errors/powershell-could-not-create-ssl-tls-secure-channel/
Last updated: 2026-11-10

**`The request was aborted: Could not create SSL/TLS secure channel.` 的意思是：Windows PowerShell（或其他 .NET Framework 程序）没能和服务器完成 TLS 握手。** 大多数情况是当前会话只提供 SSL 3 或 TLS 1.0，而服务器要求 TLS 1.2 及以上。按微软支持的方式打开 TLS 1.2 即可。问题不在证书上，关闭证书检查没有用。

## 这条报错是什么意思

这是 .NET Framework 的 TLS 握手失败异常。在 .NET Framework 里，`HttpWebRequest`、`WebClient`，以及 Windows PowerShell 5.1 的 `Invoke-WebRequest`、`Invoke-RestMethod`，握手失败时会抛出状态为 `SecureChannelFailure` 的 `WebException`。它的文字由参考源码中的两条字符串拼成：“The request was aborted: {0}.”和“Could not create SSL/TLS secure channel”，于是你看到：

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

.NET Framework 把 TLS 交给 Windows 的 Schannel 处理：操作系统版本决定能用哪些协议，.NET Framework 的设置决定进程实际提供哪些。微软的说明是，面向 .NET Framework 4.7 及以上的程序使用操作系统默认值；面向更老框架版本的进程，或者没有设置 `SchUseStrongCrypto`、`SystemDefaultTlsVersions` 注册表项的机器，可能只提供老协议。

证书信任失败的报错不一样：`Could not establish trust relationship for the SSL/TLS secure channel.`。如果你看到的是这条，说明协议协商成功了，是服务器证书被拒绝，见 [.NET remote certificate is invalid](https://ssl.sh/zh/errors/dotnet-remote-certificate-is-invalid/)。

跑了好几年的脚本突然报错，通常是对方服务器关闭了 TLS 1.0 和 1.1，脚本本身没变。TLS 1.0、1.1 已被 RFC 8996 正式废弃，服务器和云服务陆续只保留 TLS 1.2 和 1.3，而老机器上的 Windows PowerShell 默认可能还只提供 TLS 1.0。排查时先看本机会话提供哪些协议，再看服务器接受哪些协议。

## 常见原因（按出现频率排序）

这个报错有 5 种常见原因，排第一的是当前会话没有提供 TLS 1.2。

### 1. 当前会话没有提供 TLS 1.2

- **确认：**

```powershell
[Net.ServicePointManager]::SecurityProtocol
$PSVersionTable.PSVersion
```

输出 `Ssl3, Tls` 说明没有提供 TLS 1.2；输出 `SystemDefault` 或包含 `Tls12`，则不是这个原因。

- **修复：** 为当前会话开启 TLS 1.2，或者通过注册表整机开启（命令见下文）。

### 2. Windows 版本不支持服务器要求的东西

微软的 Schannel 支持表显示：Windows 7 和 Server 2008 R2 上 TLS 1.1、1.2 默认禁用；TLS 1.3 从 Windows 11 和 Windows Server 2022 才开始支持。服务器只接受 TLS 1.3，或只开放老版 Windows 没有的加密套件，就连不上。

- **确认：** 用 [SSL 检测工具](https://ssl.sh/zh/tools/ssl-checker/)查看服务器支持的协议和套件；客户端上运行 `Get-TlsCipherSuite | Select-Object Name`（Windows 10 / Server 2016 及以上）。
- **修复：** 在老系统上为 Schannel 开启 TLS 1.2；请服务器管理员保留 TLS 1.2 和 ECDHE-GCM 套件；或者升级 Windows。

### 3. 安全加固时禁用了 Schannel 协议

安全基线和加固工具会在 `HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client` 下写入 `Enabled=0`。

- **确认：**

```powershell
Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client' -ErrorAction SilentlyContinue
```

### 4. 服务器要求客户端证书

双向 TLS 时，没有提供客户端证书，或者运行 PowerShell 的账户读不了证书私钥，握手都会失败。用 `-Certificate` 参数传入证书，并在 `certlm.msc` 里检查私钥权限。

### 5. 代理或防火墙干扰

同样的命令换个网络就正常，说明是代理或防火墙掐断了握手。读取 Schannel 写入“系统”事件日志的记录，见 [Windows Schannel 报错](https://ssl.sh/zh/errors/windows-schannel-errors/)。

## 分平台修复命令

所有修法的目标都是让进程提供 TLS 1.2：临时改当前会话，或者用注册表对整机生效。

**Windows PowerShell 5.1，仅当前会话：**

```powershell
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest https://example.com/ -UseBasicParsing
```

**整机，对所有 .NET Framework 4.x 程序生效（管理员 PowerShell，之后重启受影响的程序）：**

```powershell
$keys = 'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319',
        'HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319'
foreach ($k in $keys) {
    New-ItemProperty -Path $k -Name SchUseStrongCrypto -Value 1 -PropertyType DWord -Force | Out-Null
    New-ItemProperty -Path $k -Name SystemDefaultTlsVersions -Value 1 -PropertyType DWord -Force | Out-Null
}
```

微软把这两项设为 1 列为最安全的取值。改动会影响这台机器上所有 .NET Framework 程序，改完要测试业务系统。

**老版 Windows（7 / Server 2008 R2）：为 Schannel 客户端开启 TLS 1.2：**

```powershell
$p = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client'
New-Item -Path $p -Force | Out-Null
New-ItemProperty -Path $p -Name Enabled -Value 1 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $p -Name DisabledByDefault -Value 0 -PropertyType DWord -Force | Out-Null
```

改完重启。这些系统已经停止支持，应该安排替换。

**PowerShell 7（pwsh）：** 它的 Web cmdlet 基于 `HttpClient`，使用操作系统默认值。确实需要限制版本时用 `-SslProtocol`：

```powershell
Invoke-RestMethod https://example.com/api -SslProtocol Tls12
```

在 PowerShell 7 里出错时，报错会变成 [The SSL connection could not be established](https://ssl.sh/zh/errors/dotnet-ssl-connection-could-not-be-established/) 那一类 .NET 消息。

**国内常见场景：** 不少单位的老服务器上还跑着多年前写的 PowerShell 脚本，对接的第三方接口一旦关闭 TLS 1.0/1.1，这些脚本就会突然报这个错。最省事的办法是在这些机器上统一设置上面两组注册表项；能升级到 PowerShell 7 的，顺手迁移过去。

## 不推荐：关闭证书校验

Windows PowerShell 里的 `[Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }`，或 PowerShell 7 的 `-SkipCertificateCheck`，修不了协议问题，却会让会话中的每个请求都接受伪造证书。微软自己的 `-SkipCertificateCheck` 文档就写着它不安全，只适用于测试时访问使用自签名证书的已知主机。也不要为了“兼容”把 `Ssl3` 或 `Tls` 加进 `SecurityProtocol`，那等于重新启用已废弃的协议。

更安全的替代办法：提供 TLS 1.2（会话里加一行，或者改注册表）；能用 `SystemDefault` 就用；升级或替换不支持 TLS 1.2 的系统；证书信任问题靠安装正确的根证书解决，而不是跳过检查。

## 怎么确认已经修好

修好的标志是会话提供 TLS 1.2，请求返回 HTTP 状态码而不是抛异常。

```powershell
[Net.ServicePointManager]::SecurityProtocol
(Invoke-WebRequest https://example.com/ -UseBasicParsing).StatusCode
```

第一行应显示包含 `Tls12`（改完注册表、新开 PowerShell 窗口后则可能显示 `SystemDefault`），请求应返回 `200` 或其他 HTTP 状态码，而不是抛异常。TLS 1.3 带来的变化见 [TLS 1.3 详解](https://ssl.sh/zh/learn/tls-1-3/)；服务器归你管的话，用 [TLS 配置生成器](https://ssl.sh/zh/tools/tls-config-generator/)生成一份新老客户端都能用的配置。

如果改完注册表还是不行，打开“事件查看器 → Windows 日志 → 系统”，筛选来源为 Schannel 的事件，里面通常会写明握手失败时的告警类型，可以判断是协议不匹配、加密套件不匹配还是证书问题。修好之后，把脚本里临时加的证书回调代码删掉。
