[{"content":" 环境：Windows 11 + PowerShell 7.6.5 + Windows Terminal 1.24 症状：每次打开 PowerShell 7，要等十几秒才出现输入行 结论：国内网络下 ctldl.windowsupdate.com 不可达，导致证书信任列表（CTL）下载超时 15 秒。关闭根证书自动更新后彻底解决。\n一、排查过程 1. 第一嫌疑人：PowerToys CommandNotFound 模块 打开 profile 检查（路径：C:\\Users\\\u0026lt;用户名\u0026gt;\\Documents\\PowerShell\\Microsoft.PowerShell_profile.ps1），发现里面有：\nImport-Module -Name Microsoft.WinGet.CommandNotFound 实测数据：\n场景 耗时 pwsh -NoProfile -Command \u0026quot;exit\u0026quot; ~0.3 秒 pwsh -Command \u0026quot;exit\u0026quot;（带 profile） ~17 秒 冷启动单独导入该模块 ~58 秒 这是 PowerToys 的\u0026quot;命令未找到时建议 winget 安装\u0026quot;功能，启动时要读 winget 索引，是已知慢点。\n处理：卸载 PowerToys、清空 profile、删除模块残留目录：\nC:\\Users\\\u0026lt;用户名\u0026gt;\\Documents\\PowerShell\\Modules\\Microsoft.WinGet.CommandNotFound 注意：仅删 profile 里的 Import-Module 行即可解决启动慢，模块文件残留不影响速度。另外 PowerToys 卸载后注册表里可能仍有残留条目，属正常现象。\n2. 第二嫌疑人：PSReadLine 清完之后依然要十几秒。进一步测试：\n# 交互模式（会加载 PSReadLine） \u0026#34;exit\u0026#34; | pwsh -NoLogo # 15.4 秒 # 非交互模式 pwsh -NoProfile -Command \u0026#34;...\u0026#34; # 0.3 秒 # 换其他模块对照 pwsh -NoProfile -Command \u0026#34;Import-Module CimCmdlets\u0026#34; # 0.4 秒 pwsh -NoProfile -Command \u0026#34;Import-Module PSReadLine\u0026#34; # 15.4 秒 规律非常明显：\n精确 15 秒，每次都是\n卡住期间 CPU 几乎无占用\n只有 PSReadLine 这类签名模块慢，普通模块不慢\nGet-PSDrive 在新进程首次运行也同样卡 15 秒\n这是典型的网络 I/O 超时特征，而不是计算慢。\n3. 官方文档的线索 PowerShell 官方文档《Troubleshoot PowerShell startup issues》明确记载：\n如果 pwsh -noninteractive 启动很快，那么问题很可能出在证书吊销列表（CRL）检查上。.NET 运行时在验证数字签名时会检查 CRL 以确保证书仍然有效。在断网环境下无法访问互联网上的 CRL，默认超时是 15 秒。\n先按文档尝试了降低超时的注册表方案：\nNew-ItemProperty -Path \u0026#34;HKLM:\\SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CertDllCreateCertificateChainEngine\\Config\u0026#34; -Name \u0026#34;ChainUrlRetrievalTimeoutMilliseconds\u0026#34; -Value 1000 -PropertyType DWord -Force 没有效果——说明卡的不是 CRL 本身，而是别的东西。\n4. 抓现场：卡住时进程在连谁 启动一个卡住的进程，第 6 秒时抓它的 TCP 连接：\n$p = Start-Process pwsh -ArgumentList \u0026#39;-NoProfile\u0026#39;,\u0026#39;-Command\u0026#39;,\u0026#39;Import-Module PSReadLine\u0026#39; -PassThru -WindowStyle Hidden Start-Sleep -Seconds 6 Get-NetTCPConnection -OwningProcess $p.Id 结果：\nRemoteAddress RemotePort State 223.106.78.79 80 SynSent 进程在等一个永远握手不成功的 HTTP 连接。223.106.78.79 不是微软的 IP（DNS 污染返回的假地址）。\n5. 定位域名 对比系统 DNS 和公共 DNS 的解析结果：\nctldl.windowsupdate.com 系统DNS: 223.106.78.78, 223.87.195.118, 223.106.78.79 ← 假 IP 阿里DNS: 117.68.54.123 ... ← 也连不上 真凶就是 ctldl.windowsupdate.com——Windows 下载\u0026quot;证书信任列表（Certificate Trust List）\u0026ldquo;的服务器。PowerShell 新进程做证书链验证时，Windows 会先去下载最新的 CTL，在你的网络环境下这个域名根本连不上，于是每次都卡满 15 秒超时。\n换 DNS 也没用：两个渠道返回的 IP 实测均不可达。\n二、最终修复 在管理员终端运行，关闭根证书自动更新：\nNew-Item -Path \u0026#34;HKLM:\\SOFTWARE\\Policies\\Microsoft\\SystemCertificates\\AuthRoot\u0026#34; -Force | Out-Null New-ItemProperty -Path \u0026#34;HKLM:\\SOFTWARE\\Policies\\Microsoft\\SystemCertificates\\AuthRoot\u0026#34; -Name \u0026#34;DisableRootAutoUpdate\u0026#34; -Value 1 -PropertyType DWord -Force 效果：启动从 15+ 秒恢复到 0.3 秒左右。\n安全性说明：\n系统已内置的根证书全部继续有效，正常上网不受影响\n根证书也会随 Windows 大版本更新而刷新\n损失的只是\u0026quot;自动增量下载新根证书\u0026rdquo;，而这一步在你的网络下本来就从没成功过（一直在超时），等于零损失\n附：之前改的 CRL 超时可以还原 Remove-ItemProperty -Path \u0026#34;HKLM:\\SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CertDllCreateCertificateChainEngine\\Config\u0026#34; -Name \u0026#34;ChainUrlRetrievalTimeoutMilliseconds\u0026#34; 三、以后想更新根证书怎么办 方法1：一键拉取全部根证书（推荐） # 从 Windows Update 下载全部受信任根证书，打包成 roots.sst certutil -generateSSTFromWU \u0026#34;$env:USERPROFILE\\Desktop\\roots.sst\u0026#34; # 导入到本机根证书存储 Import-Certificate -FilePath \u0026#34;$env:USERPROFILE\\Desktop\\roots.sst\u0026#34; -CertStoreLocation Cert:\\LocalMachine\\Root 不受 DisableRootAutoUpdate 策略影响，是独立下载通道。\n方法2：按需导入单个根证书 实际中只有访问某网站报证书错误时才需要。去对应 CA 官网下载根证书（.cer），然后：\nImport-Certificate -FilePath \u0026#34;证书.cer\u0026#34; -CertStoreLocation Cert:\\LocalMachine\\Root 方法3：临时恢复自动更新 Set-ItemProperty \u0026#34;HKLM:\\SOFTWARE\\Policies\\Microsoft\\SystemCertificates\\AuthRoot\u0026#34; -Name DisableRootAutoUpdate -Value 0 certutil -pulse # 立即触发一次 Set-ItemProperty \u0026#34;HKLM:\\SOFTWARE\\Policies\\Microsoft\\SystemCertificates\\AuthRoot\u0026#34; -Name DisableRootAutoUpdate -Value 1 提醒：以上方法本质都从 ctldl.windowsupdate.com / Windows Update 下载，在网络不畅时依然会超时。可行姿势：哪天挂了代理或换了网络环境，跑一次方法1一步到位。\n四、排查方法论总结 先测基线：pwsh -NoProfile vs 带_profile，隔离 profile 因素 对照实验：换模块、换命令，找出\u0026quot;只有 X 慢\u0026quot;的规律 看数字特征：精确 15 秒 + 零 CPU = 网络/IO 超时，不是代码慢 抓现场：卡住瞬间用 Get-NetTCPConnection -OwningProcess 看它在连谁 查 DNS：系统 DNS vs 公共 DNS 对比，识别污染 善用官方文档：PowerShell 文档对启动慢有专门章节，\u0026ldquo;非交互快 = CRL 检查\u0026quot;这条经验直接命中方向 常用排查命令速查 # 对比有无 profile 的启动耗时 \u0026#34;无Profile: \u0026#34; + (Measure-Command { pwsh -NoProfile -Command \u0026#34;exit\u0026#34; }).TotalMilliseconds + \u0026#34; ms\u0026#34; \u0026#34;有Profile: \u0026#34; + (Measure-Command { pwsh -Command \u0026#34;exit\u0026#34; }).TotalMilliseconds + \u0026#34; ms\u0026#34; # 测模块加载耗时 Measure-Command { pwsh -NoProfile -Command \u0026#34;Import-Module PSReadLine\u0026#34; } # 抓卡住进程的网络连接 Get-NetTCPConnection -OwningProcess \u0026lt;PID\u0026gt; # 对比 DNS 解析 Resolve-DnsName ctldl.windowsupdate.com Resolve-DnsName ctldl.windowsupdate.com -Server 223.5.5.5 ","permalink":"https://cdwc233.github.io/posts/powershell-slow-startup/","summary":"国内网络下 ctldl.windowsupdate.com 不可达，导致证书信任列表下载超时 15 秒。完整排查过程与最终修复方案。","title":"PowerShell 7 启动慢 15 秒排查记"},{"content":"开张啦 这是使用 Hugo + PaperMod 主题搭建的个人博客，托管在 GitHub Pages 上。\n我能写什么 Markdown 文章：支持代码高亮、表格、图片 标签和归档：自动整理文章 全文搜索：右上角搜索按钮 深色模式：跟随系统或手动切换 代码示例 def hello(): print(\u0026#34;Hello, 油条的小站!\u0026#34;) 写作很快乐，坚持最难得。\n","permalink":"https://cdwc233.github.io/posts/hello-world/","summary":"我的第一篇博客，小站正式开张！","title":"Hello World"}]