PowerShell 7.6.6 启动崩溃:更新通知中的负数宽度

太阳作者太阳
原创内容采用 CC-4.0 协议发布,转载请注明出处

打开 PowerShell 7.6.6,版本号刚出来,进程就退出了:totalWidth ('-17') must be a non-negative value。连提示符都没见到。

顺着堆栈查下去,出错的是启动时显示更新通知的代码。先关闭通知可以绕过这条调用路径。本文保留这次的报错和上游分析,关闭通知后的本机启动结果还没有验证。

报错发生在什么位置

日志中与问题有关的几行如下,重复的入口堆栈已省略:

PowerShell 7.6.6
Process terminated.
totalWidth ('-17') must be a non-negative value. (Parameter 'totalWidth')
Actual value was -17.

System.ArgumentOutOfRangeException:
   at System.String.PadRight(Int32 totalWidth, Char paddingChar)
   at Microsoft.PowerShell.UpdatesNotification.ShowUpdateNotification(PSHostUserInterface hostUI)
   at Microsoft.PowerShell.ConsoleHost.Start(String bannerText, String helpText, Boolean issProvidedExternally)

PadRight 负责给字符串补空格,却收到了负数宽度。异常从 ShowUpdateNotification 传到控制台启动入口,进程随之退出。一个通知框的排版错误,就这样让整个 PowerShell 无法启动。

为什么宽度会变成 -17

PowerShell 上游问题 #28131里有相同的堆栈。通知排版代码假设第一行最长,用它的长度减去其他行的长度,计算需要补多少空格。换成中文后,第一行却比下面的链接短。

该 issue 下有人测量了 7.6.6 稳定版的简体中文通知资源:第一行 38 个字符,第三行 58 个字符。代入第三行的补齐公式:

38 - 58 + 3 = -17

算出来正好是日志里的 -17。这些字符数来自上游报告,本机没有重新提取资源测量。

从 CMD 关闭更新通知

PowerShell 进不去时,先从开始菜单或运行窗口打开 CMD(命令提示符),执行:

setx POWERSHELL_UPDATECHECK Off

微软更新通知文档说明,POWERSHELL_UPDATECHECK=Off 会关闭更新通知。这个变量必须在 PowerShell 启动前设置,写进 $PROFILE 已经太晚了。

然后退出并重新打开终端所在的应用。用 Windows Terminal 就关闭所有 Terminal 窗口,用 VS Code 或 Codex 的集成终端就重开对应应用。旧进程仍然保留原来的环境变量,只开一个新标签页可能还会崩溃。

也可以留在当前 CMD 窗口,临时设置变量后直接启动 PowerShell:

set POWERSHELL_UPDATECHECK=Off
pwsh

这里的 set 是 CMD 语法,设置会传给随后启动的 pwsh。前面的 setx 会保存设置,但不会改变当前 CMD 窗口的环境变量。这一区别见微软 setx 命令文档。

重新启动后检查

能进入 PowerShell 提示符后,检查版本和环境变量:

$PSVersionTable.PSVersion
$env:POWERSHELL_UPDATECHECK

第二条命令应输出 Off。如果为空,先确认终端所在的应用是否已经彻底退出过。如果设置为 Off 后仍然在启动时崩溃,需要再看新的堆栈,确认出错位置。

关闭通知只是绕过了出错的代码,排版缺陷还在。以后仍需通过原来的安装渠道更新 PowerShell;微软文档也说明,这个通知功能本身不负责自动升级。

什么时候恢复通知

2026 年 10 月 20 日查阅时,上游问题 #28131 仍然打开。这次故障只在需要显示更新通知时触发,所以升级后暂时能启动,还不足以说明问题已经修好。

等后续版本确认修复,再删除这次添加的用户级变量。命令在能正常运行的 PowerShell 中执行:

[Environment]::SetEnvironmentVariable('POWERSHELL_UPDATECHECK', $null, 'User')

这条命令通过 .NET 方法删除用户级设置,用法见PowerShell 环境变量文档。执行后同样需要退出并重开终端所在的应用。