Download Chrome with curl.exe, then BITS, then Invoke-WebRequest
Invoke-WebRequest pushes every buffer through the pipeline and is the slowest of the three by a wide margin; curl.exe ships in System32 on every supported Windows and resumes a partial file with -C -, which matters on a 166 MB download that gets interrupted. Also checks the finished file against Content-Length, because a truncated MSI fails in msiexec with an error that says nothing about why. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f52efd73c6
commit
61d6305ded
@@ -92,21 +92,53 @@ if (-not $Remove -and -not (Find-Chrome)) {
|
||||
|
||||
# Google's own enterprise MSI, which installs machine-wide and silently. We
|
||||
# are already elevated by this point, so this needs no second prompt.
|
||||
$url = 'https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi'
|
||||
$msi = Join-Path $env:TEMP 'googlechromestandaloneenterprise64.msi'
|
||||
Write-Host 'Google Chrome is not installed — downloading it from Google (about 160 MB).'
|
||||
|
||||
# Progress off for the duration. Windows PowerShell re-renders the progress
|
||||
# bar on every buffer, which on a 160 MB file costs far more time than the
|
||||
# transfer itself — minutes instead of seconds, looking for all the world
|
||||
# like a stalled download.
|
||||
# Three ways down, fastest first. Invoke-WebRequest is last for a reason: it
|
||||
# pushes every buffer through the PowerShell pipeline, and on Windows
|
||||
# PowerShell it also re-renders the progress bar each time, which on a file
|
||||
# this size costs more than the transfer itself — minutes rather than
|
||||
# seconds, and indistinguishable from a stall while you watch it crawl.
|
||||
$curl = Join-Path $env:SystemRoot 'System32\curl.exe'
|
||||
if (Test-Path $curl) {
|
||||
# -C - resumes a part-downloaded file rather than starting the 160 MB
|
||||
# again, which matters when this is retried after an interruption.
|
||||
& $curl -fL --retry 3 --retry-delay 2 -C - -o $msi $url
|
||||
if ($LASTEXITCODE -ne 0) { Remove-Item $msi -ErrorAction SilentlyContinue }
|
||||
}
|
||||
|
||||
if (-not (Test-Path $msi) -and (Get-Command Start-BitsTransfer -ErrorAction SilentlyContinue)) {
|
||||
try {
|
||||
Start-BitsTransfer -Source $url -Destination $msi -Priority Foreground -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Host "BITS transfer failed ($($_.Exception.Message)); falling back."
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Test-Path $msi)) {
|
||||
$previousProgress = $ProgressPreference
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
try {
|
||||
Invoke-WebRequest -Uri 'https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi' `
|
||||
-OutFile $msi -UseBasicParsing
|
||||
Invoke-WebRequest -Uri $url -OutFile $msi -UseBasicParsing
|
||||
} finally {
|
||||
$ProgressPreference = $previousProgress
|
||||
}
|
||||
}
|
||||
|
||||
# A truncated download installs as a corrupt package, with an msiexec error
|
||||
# that says nothing about the real cause.
|
||||
$expected = 0
|
||||
try {
|
||||
$expected = [int64](Invoke-WebRequest -Uri $url -Method Head -UseBasicParsing).Headers['Content-Length']
|
||||
} catch { }
|
||||
$got = (Get-Item $msi -ErrorAction SilentlyContinue).Length
|
||||
if (-not $got) { throw 'Chrome download produced no file.' }
|
||||
if ($expected -gt 0 -and $got -ne $expected) {
|
||||
Remove-Item $msi -ErrorAction SilentlyContinue
|
||||
throw "Chrome download is incomplete ($got of $expected bytes). Re-run to resume."
|
||||
}
|
||||
|
||||
Write-Host 'Installing Chrome...'
|
||||
$msiexec = Start-Process msiexec.exe -Wait -PassThru -ArgumentList @('/i', "`"$msi`"", '/qn', '/norestart')
|
||||
|
||||
Reference in New Issue
Block a user