绿色版 Chrome 设为 Win11 默认浏览器 —— 完整教程(网吧还原环境)
适用:Windows 11 23H2 (22631) / 绿色便携版 Chrome / C 盘每次开机还原、D 盘保留
效果:开机自动把 D 盘绿色 Chrome 设为默认浏览器,点 https 链接不弹任何”你要如何打开这个链接?”选择框
结论先行:三件事缺一不可——
NoNewAppAlert=1 策略 → 治”弹窗”(实测 22631 上唯一有效的开关)
- 注册 ProgID
ChromeHTML → 治”默认值指向的程序根本启动不了”
- SetUserFTA 写 UserChoice → 治”默认值本身”(带合法 Hash,不被系统重置)
Edge 开机抢占任务禁用属于可选保险,非必需(详见 §6)。
1. 原理:Windows 打开一个 https 链接时发生了什么
点链接 │ ▼ 读 HKCU\...\UrlAssociations\https\UserChoice ← ① 默认值是什么 ProgID? (带 Hash 校验) │ ▼ 读 HKCU\Software\Classes\<ProgId>\shell\open\command ← ② 这个 ProgID 怎么启动? │ ▼ [首次打开时] windows.storage.dll! CBindAndInvokeStaticVerb::ConfirmUserChoiceIfNewHandlersAvailable │ 枚举当前"已注册的浏览器处理器", 发现 UserChoice 指向的是"新面孔"? ├── 是 → 弹"你要如何打开这个链接? 仅一次/始终" ← ③ 弹窗来源 └── 读到策略 NoNewAppAlert=1 → 直接跳过, 不弹 ← 唯一可靠关闭方式
|
网吧场景为什么必弹:C 盘还原后注册表被洗空,脚本每次开机重写 Chrome 的 ProgID/Capabilities/RegisteredApplications → 对 Windows 而言 Chrome 每次开机都是”新注册的处理器” → 每次开机首点必弹一次。
为什么 Hash 手写无效:UserChoice 带 keyed Hash(对 UserSid+ProgId 等做 MAC),手改会被 Windows 判非法并重置回 Edge。SetUserFTA 内置算法能算出合法 Hash。
2. 文件清单
| 文件 |
作用 |
D:\DevTools\Set-DefaultChrome.ps1 |
主脚本(下文 §4 全文) |
D:\DevTools\SetUserFTA.exe |
Kolbicz 出品,算 Hash 写 UserChoice(kolbi.cz) |
D:\DevTools\SetChrome.log |
运行日志(D 盘不怕还原,出事查时间线) |
D:\DevTools\All-Set.bat |
开机自启入口,第 5 行左右调用主脚本 |
3. 执行顺序铁律
- NoNewAppAlert=1 必须最先写——策略到位后,后续一切”新处理器”判定都被豁免;
- ApplicationAssociationToasts 标记(若保留)必须先于 UserChoice,两者之间不插耗时操作;
- UserChoice 最后写——写早了没有意义(ProgID 还没注册);
- 全程 HKCU 为主,HKLM 策略需管理员(脚本经 All-Set.bat 提权跑时 HKLM 也能写上)。
$ErrorActionPreference = "Stop"
$chrome = "D:\AA-Program\Chrome\Application\chrome.exe" $progId = "ChromeHTML" $appName = "Google Chrome" $setUserFta = "D:\DevTools\SetUserFTA.exe"
if (-not (Test-Path $chrome)) { Write-Host "[X] chrome.exe 不存在: $chrome" -ForegroundColor Red; exit 1 } if (-not (Test-Path $setUserFta)) { Write-Host "[X] SetUserFTA.exe 不存在: $setUserFta" -ForegroundColor Red; exit 1 }
$log = "D:\DevTools\SetChrome.log" function Write-Log($msg) { "{0} {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss.fff"), $msg | Add-Content -Path $log -Encoding UTF8 } Write-Log "=== Set-DefaultChrome 开始 ==="
Write-Host "[1/5] 写入 NoNewAppAlert=1 策略 ..." -ForegroundColor Cyan foreach ($root in @("HKCU:\Software\Policies\Microsoft\Windows\Explorer", "HKLM:\Software\Policies\Microsoft\Windows\Explorer")) { try { New-Item -Path $root -Force | Out-Null New-ItemProperty -Path $root -Name "NoNewAppAlert" -PropertyType DWord -Value 1 -Force | Out-Null Write-Host "[OK] $root -> NoNewAppAlert=1" -ForegroundColor Green } catch { Write-Host "[!] $root 写入失败: $($_.Exception.Message)" -ForegroundColor Yellow } } Write-Log "[OK] NoNewAppAlert=1 已写"
Write-Host "[2/5] 预写 ApplicationAssociationToasts 标记 ..." -ForegroundColor Cyan $toasts = "HKCU:\Software\Microsoft\Windows\CurrentVersion\ApplicationAssociationToasts" New-Item -Path $toasts -Force | Out-Null foreach ($name in @("ChromeHTML_https","ChromeHTML_http","ChromeHTML_.htm","ChromeHTML_.html","ChromeHTML_.shtml")) { New-ItemProperty -Path $toasts -Name $name -PropertyType DWord -Value 0 -Force | Out-Null } Write-Log "[OK] 提示标记 5 个已写"
Write-Host "[3/5] 注册 ProgID: $progId ..." -ForegroundColor Cyan $cls = "HKCU:\Software\Classes\$progId" New-Item -Path $cls -Force | Out-Null Set-ItemProperty -Path $cls -Name "(default)" -Value "Chrome HTML Document" -Force
$appKey = "$cls\Application" New-Item -Path $appKey -Force | Out-Null Set-ItemProperty -Path $appKey -Name "ApplicationName" -Value $appName -Force Set-ItemProperty -Path $appKey -Name "ApplicationIcon" -Value "$chrome,0" -Force Set-ItemProperty -Path $appKey -Name "ApplicationDescription" -Value "Access the Internet" -Force
$cmdKey = "$cls\shell\open\command" New-Item -Path $cmdKey -Force | Out-Null $cmdValue = "`"$chrome`" --single-argument %1" Set-ItemProperty -Path $cmdKey -Name "(default)" -Value $cmdValue -Force
$iconKey = "$cls\DefaultIcon" New-Item -Path $iconKey -Force | Out-Null Set-ItemProperty -Path $iconKey -Name "(default)" -Value "$chrome,0" -Force Write-Log "[OK] ProgID 已注册"
Write-Host "[4/5] 注册浏览器应用 ..." -ForegroundColor Cyan $client = "HKCU:\Software\Clients\StartMenuInternet\$appName" New-Item -Path $client -Force | Out-Null Set-ItemProperty -Path $client -Name "(default)" -Value $appName -Force
New-Item -Path "$client\DefaultIcon" -Force | Out-Null Set-ItemProperty -Path "$client\DefaultIcon" -Name "(default)" -Value "$chrome,0" -Force
New-Item -Path "$client\shell\open\command" -Force | Out-Null Set-ItemProperty -Path "$client\shell\open\command" -Name "(default)" -Value "`"$chrome`"" -Force
$cap = "$client\Capabilities" New-Item -Path $cap -Force | Out-Null Set-ItemProperty -Path $cap -Name "ApplicationName" -Value $appName -Force Set-ItemProperty -Path $cap -Name "ApplicationDescription" -Value "Access the Internet" -Force
$urlAssoc = "$cap\URLAssociations" New-Item -Path $urlAssoc -Force | Out-Null Set-ItemProperty -Path $urlAssoc -Name "http" -Value $progId -Force Set-ItemProperty -Path $urlAssoc -Name "https" -Value $progId -Force
New-Item -Path "HKCU:\Software\RegisteredApplications" -Force | Out-Null Set-ItemProperty -Path "HKCU:\Software\RegisteredApplications" -Name $appName ` -Value "Software\Clients\StartMenuInternet\$appName\Capabilities" -Force Write-Log "[OK] 已注册为浏览器应用"
Write-Host "[5/5] 用 SetUserFTA 写 UserChoice ..." -ForegroundColor Cyan foreach ($t in @("https", "http", ".htm", ".html", ".shtml")) { & $setUserFta $t $progId | Out-Null } Write-Log "[OK] UserChoice 5 项已写"
function Check-Choice($label, $path) { $k = Get-ItemProperty -Path "Registry::$path" -ErrorAction SilentlyContinue if ($k -and $k.ProgId -eq $progId) { Write-Host (" [OK] {0,-7} -> {1}" -f $label, $k.ProgId) -ForegroundColor Green } else { Write-Host (" [X] {0,-7} -> 期望 {1}" -f $label, $progId) -ForegroundColor Red } } Check-Choice "https" "HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice" Check-Choice "http" "HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" Check-Choice ".htm" "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.htm\UserChoice" Check-Choice ".html" "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice" Check-Choice ".shtml" "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.shtml\UserChoice" Write-Log "=== Set-DefaultChrome 结束 ==="
|
5. 接入开机自启(All-Set.bat)
在 All-Set.bat 提权之后最先执行:
:: 把绿色 Chrome 设为默认 (必须每次开机跑, C 盘还原会洗掉注册表) start "" /b powershell -NoProfile -ExecutionPolicy Bypass -File "D:\DevTools\Set-DefaultChrome.ps1"
|
要点:
-ExecutionPolicy Bypass 绕过策略限制;-NoProfile 提速;
- 放在 All-Set.bat 前部,赶在用户点第一个链接之前跑完(实测 3~4 秒)。
6. 验证
Get-ItemProperty "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice" | Select ProgId,Hash
Get-ItemProperty "HKCU:\Software\Policies\Microsoft\Windows\Explorer" NoNewAppAlert
Get-Content D:\DevTools\SetChrome.log -Tail 8
|
7. 踩坑录(本方案验证过程中证伪的假设)
| 曾经的怀疑 |
真相 |
| UCPD.sys 会拦 SetUserFTA? |
不会。UCPD 只拦”无 Hash 直改”,SetUserFTA 算出合法 Hash 写入畅通 |
| UserChoice 的 Hash 会失效? |
SetUserFTA 算的 Hash 每次都有效;”重启后失效”其实是 C 盘还原把整个注册表洗了 |
| 预写”仅一次”标记能防弹窗? |
22631 无效(标记全程在位仍弹),只对部分旧版本有效 |
用 SetUserFTA get 验证? |
它显示的是”有效关联”,会假成功;必须直接读 UserChoice 项 |
| ProgID 随便起名? |
Chrome 只认 ChromeHTML,改名会一直提示”不再是默认浏览器” |
| Edge 任务是弹窗元凶? |
它确实想抢默认但全部 0x80070005 失败,与弹窗无关(弹窗源头是”新处理器”检查) |
9. FAQ
Q:点链接还是弹”你要如何打开这个链接?”
A:查 NoNewAppAlert(HKCU、HKLM 都看),并确认脚本第 1 步在 UserChoice 之前执行、All-Set.bat 确实调用了脚本(看 SetChrome.log 当天有没有记录)。
Q:Chrome 能打开,但顶部黄条提示”不是默认浏览器”?
A:第 4 步(RegisteredApplications / Capabilities)没写成功,检查后重跑。
Q:链接还是被 Edge 打开?
A:第 5 步 SetUserFTA 没跑成(看日志),或第 6 步验证里 ProgId 不是 ChromeHTML。
Q:手动跑报”禁止运行脚本”?
A:powershell -NoProfile -ExecutionPolicy Bypass -File D:\DevTools\Set-DefaultChrome.ps1。
Q:网吧母盘换了新版 Windows 还灵吗?
A:核心机制(UserChoice+Hash、NoNewAppAlert)长期稳定;若弹窗复发,先按 §7 逐项验证,再看 SetChrome.log 时间线定位。