Files
autofirmer-expanded/scripts/configure-chrome-defaults.ps1
T
Brandon LiandClaude Opus 5 8b2e78d766 Set Chrome as default and pin it, as far as Windows allows
Neither can be done for the running profile: UserChoice is hash-validated and
guarded by UCPD.sys since Feb 2024, and taskbar pinning lost its shell verb
years ago - both to stop installers helping themselves. What is supported is
policy, which applies when a profile is created, so this writes the
DefaultAssociationsConfiguration and taskbar layout XMLs for the next user and
does the two things that help the current one: a desktop shortcut, and opening
the Settings page where the browser choice actually has to be made.

Folded into the enrolment script's existing elevation so the install still
raises a single UAC prompt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 18:17:42 -05:00

127 lines
5.9 KiB
PowerShell

<#
.SYNOPSIS
Make Chrome the default browser and pin it to the taskbar, as far as Windows
permits that from a script.
.DESCRIPTION
Which is not very far, and it is worth knowing why before reading the code.
The default-browser association lives under UserChoice, whose ProgId is
validated against a hash Windows will only generate from its own Settings
dialog — and since February 2024 a kernel driver (UCPD.sys) blocks writes to
that key regardless. Tools that forge the hash exist; they are working around
a security control and Microsoft breaks them on a schedule.
Taskbar pinning lost its shell verb years ago for the same reason: to stop
installers helping themselves to the taskbar.
What is supported is policy, and policy applies when a user profile is
created — so both settings here take effect for the NEXT new user to sign in,
not for the profile running this. For the current profile the honest answers
are a desktop shortcut, which this makes, and two clicks in Settings, which
this opens for you.
Needs elevation: both policies are machine-wide.
.EXAMPLE
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\configure-chrome-defaults.ps1
#>
[CmdletBinding()]
param(
# Skip opening the Settings page at the end.
[switch]$Quiet
)
$ErrorActionPreference = 'Stop'
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
if (-not ([Security.Principal.WindowsPrincipal]$identity).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator)) {
throw 'Run this elevated — both policies are machine-wide.'
}
$chrome = @("$env:ProgramFiles\Google\Chrome\Application\chrome.exe",
"${env:ProgramFiles(x86)}\Google\Chrome\Application\chrome.exe",
"$env:LOCALAPPDATA\Google\Chrome\Application\chrome.exe") |
Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1
if (-not $chrome) { throw 'Google Chrome is not installed.' }
$dir = Join-Path $env:ProgramData 'AutoFirmer'
New-Item -ItemType Directory -Path $dir -Force | Out-Null
# ── Default browser ─────────────────────────────────────────────────────────
# Only the associations named here are overridden; everything absent from the
# file keeps whatever Windows would have chosen.
$assoc = Join-Path $dir 'default-associations.xml'
@'
<?xml version="1.0" encoding="UTF-8"?>
<DefaultAssociations>
<Association Identifier="http" ProgId="ChromeHTML" ApplicationName="Google Chrome" />
<Association Identifier="https" ProgId="ChromeHTML" ApplicationName="Google Chrome" />
<Association Identifier=".htm" ProgId="ChromeHTML" ApplicationName="Google Chrome" />
<Association Identifier=".html" ProgId="ChromeHTML" ApplicationName="Google Chrome" />
</DefaultAssociations>
'@ | Set-Content -Path $assoc -Encoding UTF8
$sys = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\System'
if (-not (Test-Path $sys)) { New-Item -Path $sys -Force | Out-Null }
New-ItemProperty -Path $sys -Name 'DefaultAssociationsConfiguration' `
-Value $assoc -PropertyType String -Force | Out-Null
Write-Host "Default-browser policy written: $assoc"
# ── Taskbar pin ─────────────────────────────────────────────────────────────
# A taskbar layout with no start layout beside it: the collection below adds the
# pin, and PinListPlacement="Replace" would wipe the user's own pins, so it is
# deliberately absent — ours is appended to whatever is already there.
$lnk = Join-Path $dir 'Google Chrome.lnk'
$shell = New-Object -ComObject WScript.Shell
$shortcut = $shell.CreateShortcut($lnk)
$shortcut.TargetPath = $chrome
$shortcut.Save()
$taskbar = Join-Path $dir 'TaskbarLayoutModification.xml'
@"
<?xml version="1.0" encoding="utf-8"?>
<LayoutModificationTemplate
xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"
xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"
xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"
Version="1">
<CustomTaskbarLayoutCollection>
<defaultlayout:TaskbarLayout>
<taskbar:TaskbarPinList>
<taskbar:DesktopApp DesktopApplicationLinkPath="$lnk" />
</taskbar:TaskbarPinList>
</defaultlayout:TaskbarLayout>
</CustomTaskbarLayoutCollection>
</LayoutModificationTemplate>
"@ | Set-Content -Path $taskbar -Encoding UTF8
$explorer = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer'
if (-not (Test-Path $explorer)) { New-Item -Path $explorer -Force | Out-Null }
New-ItemProperty -Path $explorer -Name 'StartLayoutFile' -Value $taskbar -PropertyType ExpandString -Force | Out-Null
# 0 so the Start menu itself stays the user's to rearrange; only the taskbar
# collection above is applied.
New-ItemProperty -Path $explorer -Name 'LockedStartLayout' -Value 0 -PropertyType DWord -Force | Out-Null
Write-Host "Taskbar pin policy written: $taskbar"
# ── The current profile ─────────────────────────────────────────────────────
$desktop = [Environment]::GetFolderPath('CommonDesktopDirectory')
$deskLnk = $shell.CreateShortcut((Join-Path $desktop 'Google Chrome.lnk'))
$deskLnk.TargetPath = $chrome
$deskLnk.Save()
Write-Host 'Desktop shortcut created.'
Write-Host @'
Both policies apply when a user profile is first created, so this profile is
unchanged. For this one:
* Default browser: the Settings page is opening now - pick Google Chrome
under "Web browser". Windows allows no other way.
* Taskbar: right-click Chrome and choose "Pin to taskbar".
'@
if (-not $Quiet) { Start-Process 'ms-settings:defaultapps' }