Bake in the enrolment token, and install Chrome when missing

Setup asked for a token that is the same on every machine - a token is reusable
and enrols any number of browsers - so it is a default in both scripts now and
step 7 is a plain yes/no. It is a modest secret: it lets someone enrol their own
browser into the org and nothing more, and rotating it is a console click and a
one-line change.

Both scripts also install Chrome if it is absent, from Google's enterprise MSI
and the official .deb, since enrolling a browser that is not there writes a
token nothing reads. Chromium is refused rather than substituted: no cloud
management, so it could never be enrolled - and on ARM, where Chrome is not
published at all, the Linux script says so instead of installing something that
cannot do the job.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-08-31 16:18:20 -05:00
co-authored by Claude Opus 5
parent 35dd15d584
commit 389c714caf
5 changed files with 104 additions and 28 deletions
+9 -2
View File
@@ -135,13 +135,20 @@ the console already set to force install, and Chrome keeps it updated. Run on
its own at any time: its own at any time:
```powershell ```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\enroll-chrome-management.ps1 -Token <token> powershell -NoProfile -ExecutionPolicy Bypass -File scripts\enroll-chrome-management.ps1
``` ```
```bash ```bash
sudo scripts/enroll-chrome-management.sh <token> sudo scripts/enroll-chrome-management.sh
``` ```
The enrolment token is built into both scripts — a token is reusable across any
number of machines — so there is nothing to type. Pass one explicitly to use a
different org. Chrome itself is installed first if the machine hasn't got it,
from Google's own enterprise MSI on Windows and the official .deb on Linux;
Chromium is not accepted as a substitute, because it has no cloud-management
support and can never be enrolled.
**Enrolment is not optional.** No Chromium browser will force-install an **Enrolment is not optional.** No Chromium browser will force-install an
off-store extension on an unmanaged machine, whatever the registry says — it off-store extension on an unmanaged machine, whatever the registry says — it
reads the policy and blanks it. Enrolling is what makes Chrome managed without reads the policy and blanks it. Enrolling is what makes Chrome managed without
+45 -3
View File
@@ -21,8 +21,14 @@
#> #>
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(Mandatory = $true, ParameterSetName = 'Enrol')] # Defaulted so setup is hands-off. An enrolment token is reusable and enrols
[string]$Token, # any number of browsers, which is what makes a baked-in default work at all.
# It is a modest secret: anyone holding it can enrol *their* browser into the
# org, which gets them our policies and a row in the console — it grants no
# access to the Google account or to anything else. Rotate it in Devices >
# Chrome > Managed browsers and change it here.
[Parameter(ParameterSetName = 'Enrol')]
[string]$Token = 'ce4fa6cd-e940-45f6-9086-85075d6cff34',
# Refuse to start Chrome at all if enrolment fails. Sound on a fleet, risky # Refuse to start Chrome at all if enrolment fails. Sound on a fleet, risky
# on a trading PC: a revoked token would leave you with no browser. # on a trading PC: a revoked token would leave you with no browser.
@@ -34,7 +40,10 @@ param(
# Fail instead of asking for elevation. Also the loop-breaker: the elevated # Fail instead of asking for elevation. Also the loop-breaker: the elevated
# copy is launched with this set, so it can never spawn another. # copy is launched with this set, so it can never spawn another.
[switch]$NoElevate [switch]$NoElevate,
# Fail rather than installing Chrome when it is missing.
[switch]$SkipChromeInstall
) )
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
@@ -52,6 +61,7 @@ if (-not ([Security.Principal.WindowsPrincipal]$identity).IsInRole(
# arguments are already parsed and can be passed on intact. # arguments are already parsed and can be passed on intact.
Write-Host 'Asking for administrator rights — the enrolment token is machine-level.' Write-Host 'Asking for administrator rights — the enrolment token is machine-level.'
$psArgs = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', "`"$PSCommandPath`"", '-NoElevate') $psArgs = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', "`"$PSCommandPath`"", '-NoElevate')
if ($SkipChromeInstall) { $psArgs += '-SkipChromeInstall' }
if ($Remove) { $psArgs += '-Remove' } if ($Remove) { $psArgs += '-Remove' }
else { else {
$psArgs += @('-Token', $Token) $psArgs += @('-Token', $Token)
@@ -63,6 +73,38 @@ if (-not ([Security.Principal.WindowsPrincipal]$identity).IsInRole(
exit $elevated.ExitCode exit $elevated.ExitCode
} }
# ── Chrome itself ────────────────────────────────────────────────────────────
# Enrolling a browser that is not installed would write a token nothing ever
# reads. Chromium is deliberately not accepted as a substitute: it has no
# cloud-management support, so it can never be enrolled and would stay subject
# to the off-store restriction forever.
function Find-Chrome {
foreach ($exe in @("$env:ProgramFiles\Google\Chrome\Application\chrome.exe",
"${env:ProgramFiles(x86)}\Google\Chrome\Application\chrome.exe",
"$env:LOCALAPPDATA\Google\Chrome\Application\chrome.exe")) {
if ($exe -and (Test-Path $exe)) { return $exe }
}
return $null
}
if (-not $Remove -and -not (Find-Chrome)) {
if ($SkipChromeInstall) { throw 'Google Chrome is not installed, and -SkipChromeInstall was given.' }
# Google's own enterprise MSI, which installs machine-wide and silently. We
# are already elevated by this point, so this needs no second prompt.
$msi = Join-Path $env:TEMP 'googlechromestandaloneenterprise64.msi'
Write-Host 'Google Chrome is not installed — downloading it from Google (about 120 MB).'
Invoke-WebRequest -Uri 'https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi' `
-OutFile $msi -UseBasicParsing
Write-Host 'Installing Chrome...'
$msiexec = Start-Process msiexec.exe -Wait -PassThru -ArgumentList @('/i', "`"$msi`"", '/qn', '/norestart')
Remove-Item $msi -ErrorAction SilentlyContinue
if ($msiexec.ExitCode -ne 0) { throw "Chrome install failed (msiexec exit $($msiexec.ExitCode))." }
if (-not (Find-Chrome)) { throw 'Chrome still not found after installing.' }
Write-Host 'Chrome installed.'
}
$key = 'HKLM:\SOFTWARE\Policies\Google\Chrome' $key = 'HKLM:\SOFTWARE\Policies\Google\Chrome'
if (-not (Test-Path $key)) { New-Item -Path $key -Force | Out-Null } if (-not (Test-Path $key)) { New-Item -Path $key -Force | Out-Null }
+32 -4
View File
@@ -5,13 +5,21 @@
# from a file under /etc at startup, so this needs root, and it applies to every # from a file under /etc at startup, so this needs root, and it applies to every
# user on the machine. # user on the machine.
# #
# sudo scripts/enroll-chrome-management.sh <token> # sudo scripts/enroll-chrome-management.sh # the built-in token
# sudo scripts/enroll-chrome-management.sh <token> # a different one
# sudo scripts/enroll-chrome-management.sh --remove # sudo scripts/enroll-chrome-management.sh --remove
# #
# Chrome only — Chromium builds have no cloud-management support, so a Chromium # Chrome only — Chromium builds have no cloud-management support, so a Chromium
# install cannot be enrolled and stays subject to the off-store restriction. # install cannot be enrolled and stays subject to the off-store restriction.
set -euo pipefail set -euo pipefail
# Defaulted so setup is hands-off. A token is reusable and enrols any number of
# browsers, which is what makes a baked-in default work. It is a modest secret:
# anyone holding it can enrol *their* browser into the org — our policies and a
# row in the console — and nothing more. Rotate it in Devices > Chrome > Managed
# browsers and change it here.
DEFAULT_TOKEN=ce4fa6cd-e940-45f6-9086-85075d6cff34
DIR=/etc/opt/chrome/policies/enrollment DIR=/etc/opt/chrome/policies/enrollment
TOKEN_FILE="$DIR/CloudManagementEnrollmentToken" TOKEN_FILE="$DIR/CloudManagementEnrollmentToken"
@@ -19,7 +27,6 @@ info() { printf ' %s\n' "$1"; }
fail() { printf '\n\033[1;31mERROR: %s\033[0m\n' "$1" >&2; exit 1; } fail() { printf '\n\033[1;31mERROR: %s\033[0m\n' "$1" >&2; exit 1; }
[ "$(id -u)" -eq 0 ] || fail "run this with sudo — the token lives under /etc" [ "$(id -u)" -eq 0 ] || fail "run this with sudo — the token lives under /etc"
[ $# -ge 1 ] || fail "usage: $0 <enrollment-token> | --remove"
if [ "$1" = "--remove" ]; then if [ "$1" = "--remove" ]; then
rm -f "$TOKEN_FILE" "$DIR/CloudManagementEnrollmentOptions" rm -f "$TOKEN_FILE" "$DIR/CloudManagementEnrollmentOptions"
@@ -30,12 +37,33 @@ if [ "$1" = "--remove" ]; then
exit 0 exit 0
fi fi
[ -d /etc/opt/chrome ] || fail "no /etc/opt/chrome — this is for Google Chrome, not Chromium" TOKEN="${1:-$DEFAULT_TOKEN}"
# Enrolling a browser that is not installed would write a token nothing reads.
# Chromium is not a substitute: it has no cloud-management support, so it can
# never be enrolled, and Google publishes Chrome for x86_64 only — on a Pi there
# is no version of this that works, and saying so beats installing something
# that cannot do the job.
if ! command -v google-chrome >/dev/null 2>&1 && [ ! -x /opt/google/chrome/chrome ]; then
ARCH=$(uname -m)
[ "$ARCH" = "x86_64" ] || fail "Google Chrome is not published for $ARCH. Chromium cannot be enrolled — this machine cannot run the extension."
command -v apt-get >/dev/null || fail "Chrome is missing and this is not an apt system — install Google Chrome, then re-run"
info "Google Chrome is not installed — fetching it from Google (about 120 MB)"
DEB=$(mktemp --suffix=.deb)
curl -fsSL -o "$DEB" https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \
|| fail "could not download Chrome"
# apt rather than dpkg: it pulls the dependencies a bare dpkg -i would leave
# half-configured.
DEBIAN_FRONTEND=noninteractive apt-get install -y "$DEB" >/dev/null || fail "Chrome install failed"
rm -f "$DEB"
info "Chrome installed"
fi
mkdir -p "$DIR" mkdir -p "$DIR"
# The file must contain the token and nothing else: no quotes, no newline noise, # The file must contain the token and nothing else: no quotes, no newline noise,
# no filename extension. Chrome reads it verbatim. # no filename extension. Chrome reads it verbatim.
printf '%s' "$1" > "$TOKEN_FILE" printf '%s' "$TOKEN" > "$TOKEN_FILE"
chmod 644 "$TOKEN_FILE" chmod 644 "$TOKEN_FILE"
info "wrote $TOKEN_FILE" info "wrote $TOKEN_FILE"
+7 -8
View File
@@ -150,16 +150,15 @@ echo
info "[7/7] Chrome extension" info "[7/7] Chrome extension"
info " Enrols this machine's Chrome, after which the extension installs" info " Enrols this machine's Chrome, after which the extension installs"
info " itself from the Admin console and stays updated on its own." info " itself from the Admin console and stays updated on its own."
info " The token is in the Admin console under Devices > Chrome >" info " Installs Chrome first if it is not here yet. Needs sudo."
info " Managed browsers. Blank to skip." read -r -p " Set this up now? [Y/n] " DOEXT
read -r -p " Enrollment token: " ENROLTOKEN
EXTPOLICY=0 EXTPOLICY=0
if [ -n "${ENROLTOKEN:-}" ]; then if [ "${DOEXT,,}" != "n" ]; then
if sudo bash scripts/enroll-chrome-management.sh "$ENROLTOKEN"; then EXTPOLICY=1; else if sudo bash scripts/enroll-chrome-management.sh; then EXTPOLICY=1; else
warn "enrolment failed - re-run: sudo scripts/enroll-chrome-management.sh <token>" warn "enrolment failed - re-run: sudo scripts/enroll-chrome-management.sh"
fi fi
else else
info " Skipped. Run: sudo scripts/enroll-chrome-management.sh <token>" info " Skipped. Run: sudo scripts/enroll-chrome-management.sh"
fi fi
# ── summary ───────────────────────────────────────────────────────────────── # ── summary ─────────────────────────────────────────────────────────────────
@@ -186,7 +185,7 @@ if [ "$EXTPOLICY" -eq 1 ]; then
info " and the extension installs itself within a minute or two." info " and the extension installs itself within a minute or two."
else else
info " - Enrol Chrome so it can install the extension:" info " - Enrol Chrome so it can install the extension:"
info " sudo scripts/enroll-chrome-management.sh <token>" info " sudo scripts/enroll-chrome-management.sh"
fi fi
info " - Add your firm credentials on the dashboard's Settings page" info " - Add your firm credentials on the dashboard's Settings page"
if [ -n "${WAYLAND_DISPLAY:-}" ] && [ -z "${DISPLAY:-}" ]; then if [ -n "${WAYLAND_DISPLAY:-}" ] && [ -z "${DISPLAY:-}" ]; then
+11 -11
View File
@@ -335,14 +335,14 @@ echo.
echo [7/7] Chrome extension echo [7/7] Chrome extension
echo Enrols this machine's Chrome, after which the extension installs echo Enrols this machine's Chrome, after which the extension installs
echo itself from the Admin console and stays updated on its own. echo itself from the Admin console and stays updated on its own.
echo The token is in the Admin console under echo Installs Chrome first if it is not here yet.
echo Devices ^> Chrome ^> Managed browsers. Blank to skip. set "DOEXT="
set "ENROLTOKEN=" set /p "DOEXT= Set this up now? [Y/n] "
set /p "ENROLTOKEN= Enrollment token: " if /i "%DOEXT%"=="n" goto :ext_skipped
if not defined ENROLTOKEN goto :ext_skipped REM The enrolment token is built into the script, so there is nothing to type.
REM The token is machine-scoped, so this raises a UAC prompt and only this. The REM It is machine-scoped, so this raises a UAC prompt - the only one in this
REM script asks for elevation itself; nothing else in this installer needs it. REM installer, and the script asks for it itself.
powershell -NoProfile -ExecutionPolicy Bypass -File "%TARGET%\scripts\enroll-chrome-management.ps1" -Token "%ENROLTOKEN%" powershell -NoProfile -ExecutionPolicy Bypass -File "%TARGET%\scripts\enroll-chrome-management.ps1"
if errorlevel 1 ( if errorlevel 1 (
echo [!] Enrolment failed. Re-run scripts\enroll-chrome-management.ps1 with echo [!] Enrolment failed. Re-run scripts\enroll-chrome-management.ps1 with
echo a fresh token from the Admin console to try again. echo a fresh token from the Admin console to try again.
@@ -353,8 +353,8 @@ if errorlevel 1 (
goto :ext_done goto :ext_done
:ext_skipped :ext_skipped
echo Skipped. Run scripts\enroll-chrome-management.ps1 -Token ^<token^> echo Skipped. Run scripts\enroll-chrome-management.ps1 later;
echo later; until then this machine gets no extension. echo until then this machine gets no extension.
set "EXTPOLICY=0" set "EXTPOLICY=0"
:ext_done :ext_done
@@ -400,7 +400,7 @@ if "%EXTPOLICY%"=="1" (
echo and the extension installs itself within a minute or two. echo and the extension installs itself within a minute or two.
) else ( ) else (
echo - Enrol Chrome so it can install the extension: echo - Enrol Chrome so it can install the extension:
echo scripts\enroll-chrome-management.ps1 -Token ^<token^> echo scripts\enroll-chrome-management.ps1
) )
echo - Add your firm credentials on the dashboard's Settings page echo - Add your firm credentials on the dashboard's Settings page
echo. echo.