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>
127 lines
5.9 KiB
PowerShell
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' }
|