xetup/scripts/11-dell-update.ps1
X9 Dev 5e01826a49
All checks were successful
release / build-and-release (push) Successful in 24s
feat: state machine for reboot-resume across Windows Update cycles
xetup.exe now acts as an orchestrator across system reboots:
- PS scripts exit 9 to signal "reboot needed, re-run me" (WU) or
  "done but reboot needed to finalize" (Dell BIOS)
- On exit 9: xetup saves state.json, ensures adminx9 account,
  copies itself to stable path, enables autologon, registers
  X9-Resume scheduled task (AtLogOn adminx9, RunLevel Highest)
- On resume: loads pending steps from state, continues seamlessly
  with "Pokracuji po restartu..." label in the run window
- On completion: disables autologon, removes X9-Resume task,
  deletes state file, shows summary with accumulated results
  across all reboot rounds

New packages: internal/state, internal/prereboot
Script 12: simplified to exit 0 (done) or exit 9 (reboot needed)
Script 11: exit 9 when DCU exit code 1 (BIOS staged, reboot needed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 17:09:53 +02:00

163 lines
6.8 KiB
PowerShell

<#
.SYNOPSIS
Detects Dell hardware, installs Dell Command | Update, and applies all available updates.
.DESCRIPTION
Checks Win32_ComputerSystem.Manufacturer - if not Dell, the step exits silently without
error so the same deployment script works on any hardware. On Dell machines, installs
Dell Command | Update (Universal) via winget and immediately runs /applyUpdates with
-reboot=disable. This covers drivers, firmware, and BIOS. BIOS and firmware updates are
staged at this point and finalize automatically during the restart that closes the
deployment. The operator does not need to run a separate update pass after setup.
.ITEMS
detekce-dell-hw-win32-computersystem: Reads Win32_ComputerSystem.Manufacturer. If the string does not contain "Dell", the entire step is skipped without error. The deployment continues normally on HP, Lenovo, or any other brand.
instalace-dell-command-update-via-winget: Installs Dell.CommandUpdate.Universal silently via winget. This is the current DCU generation (v5+) that supports Latitude, OptiPlex, Precision, Vostro, and XPS on Win10 and Win11.
spusteni-vsech-aktualizaci-drivery-firmware-bios: Runs dcu-cli.exe /applyUpdates -silent -reboot=disable. Covers driver, firmware, and BIOS categories in a single pass. The -reboot=disable flag prevents DCU from rebooting mid-deployment.
bios-firmware-staging-reboot: BIOS and firmware updates are staged by DCU and finalize on the next system restart. The deployment already ends with a restart (step 09 - computer rename), so no extra reboot is needed.
#>
param(
[object]$Config,
[string]$LogFile
)
$ErrorActionPreference = "Continue"
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
$null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue
Add-Content -Path $LogFile -Value $line -Encoding UTF8
switch ($Level) {
"OK" { Write-Host $line -ForegroundColor Green }
"ERROR" { Write-Host $line -ForegroundColor Red }
"WARN" { Write-Host $line -ForegroundColor Yellow }
"STEP" { Write-Host $line -ForegroundColor Cyan }
default { Write-Host $line }
}
}
function Get-Feature {
param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)
try {
if ($null -eq $Cfg) { return $Default }
$stepFeatures = $Cfg.features.$StepID
if ($null -eq $stepFeatures) { return $Default }
$val = $stepFeatures.$FeatureID
if ($null -eq $val) { return $Default }
return [bool]$val
} catch { return $Default }
}
# -----------------------------------------------------------------------
# Detect Dell hardware
# -----------------------------------------------------------------------
Write-Log "Checking hardware manufacturer" -Level INFO
try {
$cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
$manufacturer = $cs.Manufacturer
$model = $cs.Model
Write-Log " Manufacturer: $manufacturer Model: $model" -Level INFO
}
catch {
Write-Log " Failed to query Win32_ComputerSystem: $_" -Level ERROR
return
}
if ($manufacturer -notmatch "Dell") {
Write-Log "Not a Dell machine ($manufacturer) - step skipped" -Level WARN
return
}
Write-Log "Dell confirmed: $model" -Level OK
# -----------------------------------------------------------------------
# Install Dell Command | Update via winget
# -----------------------------------------------------------------------
Write-Log "Installing Dell Command | Update (Universal)..." -Level STEP
$wingetArgs = @(
"install",
"--id", "Dell.CommandUpdate.Universal",
"--silent",
"--accept-package-agreements",
"--accept-source-agreements"
)
$wingetOutput = & winget @wingetArgs 2>&1
$wingetExit = $LASTEXITCODE
$wingetOutput | ForEach-Object { Write-Log " [winget] $_" -Level INFO }
if ($wingetExit -ne 0 -and $wingetExit -ne 1638) { # 1638 = already installed
Write-Log " winget exit code $wingetExit - checking if DCU is already present" -Level WARN
}
# Locate dcu-cli.exe (path is the same for x64 and Universal edition)
$dcuCandidates = @(
"C:\Program Files\Dell\CommandUpdate\dcu-cli.exe",
"C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe"
)
$dcuCli = $dcuCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
if (-not $dcuCli) {
Write-Log " dcu-cli.exe not found - cannot run updates" -Level ERROR
return
}
Write-Log " dcu-cli.exe found: $dcuCli" -Level OK
# -----------------------------------------------------------------------
# Run updates - categories controlled by feature flags
# -reboot=disable -> no mid-deployment reboot; BIOS/firmware staged for next restart
# -----------------------------------------------------------------------
$runDrivers = Get-Feature $Config "dellUpdate" "drivers"
$runBios = Get-Feature $Config "dellUpdate" "bios"
if (-not $runDrivers -and -not $runBios) {
Write-Log "Both drivers and bios features disabled - skipping update run" -Level INFO
} else {
# Build update type list from enabled features
$updateTypes = @()
if ($runDrivers) {
$updateTypes += "driver"
$updateTypes += "firmware"
}
if ($runBios) {
$updateTypes += "bios"
}
$updateTypeArg = $updateTypes -join ","
Write-Log "Running Dell Command | Update (updateType=$updateTypeArg, no auto-reboot)..." -Level STEP
Write-Log " This may take several minutes depending on available updates" -Level INFO
$dcuOutput = & $dcuCli /applyUpdates -silent -reboot=disable "-updateType=$updateTypeArg" 2>&1
$exitCode = $LASTEXITCODE
$dcuOutput | ForEach-Object { Write-Log " [DCU] $_" -Level INFO }
Write-Log " DCU exit code: $exitCode" -Level INFO
# Dell Command | Update exit codes:
# 0 = completed, no updates required or updates applied (no reboot needed)
# 1 = updates applied, reboot required to finalize BIOS/firmware
# 5 = no applicable updates found for this system
# others = error or partial failure
switch ($exitCode) {
0 {
Write-Log "Dell Command | Update: complete (no reboot required)" -Level OK
}
1 {
Write-Log "Dell Command | Update: updates staged - BIOS/firmware will finalize on restart" -Level OK
Write-Log "Step 11 complete - signalling reboot needed (exit 9)" -Level OK
exit 9
}
5 {
Write-Log "Dell Command | Update: no applicable updates for this model" -Level OK
}
default {
Write-Log "Dell Command | Update: exit code $exitCode - review DCU log in C:\ProgramData\Dell\UpdateService\Logs" -Level WARN
}
}
}
Write-Log "Step 11 complete" -Level OK