kms-website: reboot-aware ODT failure handling (exit 1603) + richer C2R log capture
setup.exe exit 1603 right after removing the bundled consumer Office almost always means the old install is pending a reboot. The script handed users a bare 1603; now it explains it. Changes: - Test-RebootRequiredHard (CBS/WU only) GATES Reinstall-OfficeVL before the ~3 GB download, so a pending reboot stops early with reboot+re-run guidance instead of failing with 1603. - Invoke-Odt failure path detects pending-reboot / 1603 and tells the user to reboot + re-run; ships reboot status in telemetry. - Get-OdtLogTail also searches %TEMP% (where the C2R client logs the real error) and prefers error-bearing lines, so a failure no longer reports an empty log.
This commit is contained in:
parent
3d31a39099
commit
07f88b8f1f
1 changed files with 40 additions and 11 deletions
|
|
@ -259,17 +259,24 @@ $script:ODT_URL = $(if ($env:KMS_ODT_URL) { $env:KMS_ODT_URL } else { 'https:/
|
||||||
# of a bare "ospp.vbs not found". Cleared at the start of every Invoke-Odt run.
|
# of a bare "ospp.vbs not found". Cleared at the start of every Invoke-Odt run.
|
||||||
$script:OdtLogDir = Join-Path $env:TEMP 'kms-odt-logs'
|
$script:OdtLogDir = Join-Path $env:TEMP 'kms-odt-logs'
|
||||||
|
|
||||||
# Tail of the newest ODT log - the setup.exe error code lives here on failure.
|
# Tail of the most relevant ODT / Click-to-Run log. ODT's own log goes to
|
||||||
function Get-OdtLogTail([int]$lines = 20) {
|
# OdtLogDir, but the DETAILED failure behind a 1603 is written by the C2R client
|
||||||
$log = Get-ChildItem -Path $script:OdtLogDir -Filter *.log -ErrorAction SilentlyContinue |
|
# to %TEMP%. Search both, newest first, and prefer error-bearing lines so the tail
|
||||||
Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
# actually explains the failure instead of being empty.
|
||||||
if (-not $log) { return '' }
|
function Get-OdtLogTail([int]$lines = 25) {
|
||||||
return ((Get-Content -LiteralPath $log.FullName -Tail $lines -ErrorAction SilentlyContinue) -join ' | ')
|
$logs = Get-ChildItem -Path @($script:OdtLogDir, $env:TEMP) -Filter *.log -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.LastWriteTime -gt (Get-Date).AddMinutes(-30) } |
|
||||||
|
Sort-Object LastWriteTime -Descending | Select-Object -First 5
|
||||||
|
foreach ($log in $logs) {
|
||||||
|
$err = Get-Content -LiteralPath $log.FullName -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_ -match 'error|fail|1603|0x8|cannot|denied|reboot|in progress' } | Select-Object -Last $lines
|
||||||
|
if ($err) { return ($log.Name + ': ' + ($err -join ' | ')) }
|
||||||
|
}
|
||||||
|
if ($logs) { return ($logs[0].Name + ': ' + ((Get-Content -LiteralPath $logs[0].FullName -Tail $lines -ErrorAction SilentlyContinue) -join ' | ')) }
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
# "A reboot is pending" probe. C2R half-completes an install when a prior removal
|
# "A reboot is pending" probe (all signals) - used for advisory messages/telemetry.
|
||||||
# left the servicing stack pending - the usual cause of an install run right after
|
|
||||||
# uninstalling the bundled consumer Office.
|
|
||||||
function Test-PendingReboot {
|
function Test-PendingReboot {
|
||||||
if (Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending') { return $true }
|
if (Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending') { return $true }
|
||||||
if (Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired') { return $true }
|
if (Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired') { return $true }
|
||||||
|
|
@ -277,6 +284,14 @@ function Test-PendingReboot {
|
||||||
return [bool]$sm.PendingFileRenameOperations
|
return [bool]$sm.PendingFileRenameOperations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# STRONG reboot signals only (CBS / Windows Update) - reliably "a real reboot is
|
||||||
|
# needed". Used to GATE an install (PendingFileRenameOperations is too noisy to
|
||||||
|
# block on - it is set by lots of unrelated software).
|
||||||
|
function Test-RebootRequiredHard {
|
||||||
|
(Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending') -or
|
||||||
|
(Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired')
|
||||||
|
}
|
||||||
|
|
||||||
# Poll until the C2R install actually lands. setup.exe /configure can return before
|
# Poll until the C2R install actually lands. setup.exe /configure can return before
|
||||||
# the Click-to-Run service finishes the multi-GB install, so trust on-disk state
|
# the Click-to-Run service finishes the multi-GB install, so trust on-disk state
|
||||||
# (ospp.vbs + the product in ProductReleaseIds), not setup.exe's return. Heartbeat
|
# (ospp.vbs + the product in ProductReleaseIds), not setup.exe's return. Heartbeat
|
||||||
|
|
@ -313,9 +328,15 @@ function Invoke-Odt([string]$configXml, [string]$stepMsg) {
|
||||||
# failure - surface the log tail (carries the error code) so we can diagnose.
|
# failure - surface the log tail (carries the error code) so we can diagnose.
|
||||||
if ($code -ne 0 -and $code -ne 3010) {
|
if ($code -ne 0 -and $code -ne 3010) {
|
||||||
$tail = Get-OdtLogTail
|
$tail = Get-OdtLogTail
|
||||||
|
$reboot = Test-PendingReboot
|
||||||
Bad "Office Deployment Tool failed (setup.exe exit $code)."
|
Bad "Office Deployment Tool failed (setup.exe exit $code)."
|
||||||
if ($tail) { Write-Host " ODT log: $tail" }
|
# 1603 = fatal install error; right after removing the bundled consumer
|
||||||
Send-Diag 'odt' 'fail' "exit=$code; $tail"
|
# Office it almost always means the old install is still pending a reboot.
|
||||||
|
if ($reboot -or $code -eq 1603) {
|
||||||
|
Write-Host " A reboot is needed to finish removing the previous Office. REBOOT, then re-run the one-liner - it installs the Volume License Office directly." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
if ($tail) { Write-Host " ODT/C2R log: $tail" }
|
||||||
|
Send-Diag 'odt' 'fail' "exit=$code; reboot=$reboot; $tail"
|
||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
if ($code -eq 3010) { Warn "ODT reports a reboot is required to finish." }
|
if ($code -eq 3010) { Warn "ODT reports a reboot is required to finish." }
|
||||||
|
|
@ -325,6 +346,14 @@ function Invoke-Odt([string]$configXml, [string]$stepMsg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Reinstall-OfficeVL([string]$product, [string]$channel) {
|
function Reinstall-OfficeVL([string]$product, [string]$channel) {
|
||||||
|
# A hard pending-reboot (CBS/WU) means a prior Office removal hasn't finished;
|
||||||
|
# installing now would download ~3 GB only to fail with 1603. Stop early.
|
||||||
|
if (Test-RebootRequiredHard) {
|
||||||
|
Bad "$product install blocked: a reboot is pending (a previous Office removal needs it)."
|
||||||
|
Write-Host " REBOOT, then re-run the one-liner - it will install $product directly." -ForegroundColor Yellow
|
||||||
|
Send-Diag 'odt' 'reboot-required-before-install' $product
|
||||||
|
return $false
|
||||||
|
}
|
||||||
if (-not $channel) { $channel = if ($product -match '2021') { 'PerpetualVL2021' } elseif ($product -match '2019') { 'PerpetualVL2019' } else { 'PerpetualVL2024' } }
|
if (-not $channel) { $channel = if ($product -match '2021') { 'PerpetualVL2021' } elseif ($product -match '2019') { 'PerpetualVL2019' } else { 'PerpetualVL2024' } }
|
||||||
$xml = @"
|
$xml = @"
|
||||||
<Configuration>
|
<Configuration>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue