Files
pxe-server/scripts/Download-Drivers.ps1
cproudlock d6776f7c7f Reorganize repo, enrollment share taxonomy, Blancco USB-build fixes, v4.10 PPKGs
Workstation reorganization:
- All build/deploy/helper scripts moved into scripts/ (paths updated to use
  REPO_ROOT instead of SCRIPT_DIR so they resolve sibling dirs from the new
  depth)
- New config/ directory placeholder for site-specific overrides
- Removed stale: mok-keys/, test-vm.sh, test-lab.sh, setup-guide-original.txt,
  unattend/ (duplicate of moved playbook/FlatUnattendW10.xml)
- README.md and SETUP.md structure listings updated, dead "Testing with KVM"
  section removed
- .claude/ gitignored

Enrollment share internal taxonomy (forward-looking; existing servers
unaffected since they keep their current boot.wim with flat paths):
- Single SMB share kept (WinPE only mounts one Y: drive), but content now
  organised into ppkgs/, scripts/, config/, shopfloor-setup/, pre-install/{bios,
  installers}, installers-post/cmm/, blancco/, logs/
- README.md deployed to share root explaining each subdir
- New playbook tasks deploy site-config.json + wait-for-internet.ps1 +
  migrate-to-wifi.ps1 explicitly (were ad-hoc on legacy servers)
- BIOS subdir moved into pre-install/bios/, preinstall/ renamed to pre-install/
- startnet.cmd + startnet-template.cmd updated with new Y:\subdir\ paths
- Bumped GCCH PPKG references v4.9 -> v4.10

Blancco USB-build fixes (so next fresh USB install boots Blancco end-to-end
without the manual fixup we did against GOLD):
- grub-blancco.cfg: kernel/initrd switched HTTP -> TFTP (GRUB's HTTP module
  times out on multi-MB files); added modprobe.blacklist=iwlwifi,iwlmvm,btusb
  (WiFi drivers hang udev on Intel business PCs)
- grubx64.efi rebuilt from updated cfg
- Playbook task added to create /srv/tftp/blancco/ symlinks pointing at the
  HTTP-served binaries

run-enrollment.ps1: OOBEComplete is now set AFTER PPKG install (Win11 22H2+
hangs indefinitely if OOBEComplete is set before the bulk-enrollment PPKG runs).

Also includes deploy-bios.sh / pull-bios.sh / busybox-static / models.txt
that were sitting untracked at the repo root.
2026-04-14 16:01:02 -04:00

231 lines
8.6 KiB
PowerShell

#
# Download-Drivers.ps1 — Download selected hardware drivers from GE CDN
#
# Reads user_selections.json and HardwareDriver.json from the MCL cache
# to download only the driver packs for your selected hardware models.
# Bypasses Media Creator Lite's unreliable download mechanism.
#
# Downloads go into the MCL cache structure so Upload-Image.ps1 can
# upload them with -IncludeDrivers.
#
# Usage:
# .\Download-Drivers.ps1 (download all selected models)
# .\Download-Drivers.ps1 -ListOnly (show what would be downloaded)
# .\Download-Drivers.ps1 -CachePath "D:\MCL\Cache" (custom cache location)
# .\Download-Drivers.ps1 -Force (re-download even if already cached)
#
# Requires internet access. Run on the workstation, not the PXE server.
#
param(
[string]$CachePath = "C:\ProgramData\GEAerospace\MediaCreator\Cache",
[switch]$ListOnly,
[switch]$Force
)
function Format-Size {
param([long]$Bytes)
if ($Bytes -ge 1GB) { return "{0:N1} GB" -f ($Bytes / 1GB) }
if ($Bytes -ge 1MB) { return "{0:N1} MB" -f ($Bytes / 1MB) }
return "{0:N0} KB" -f ($Bytes / 1KB)
}
function Resolve-DestDir {
param([string]$Dir)
return ($Dir -replace '^\*destinationdir\*\\?', '')
}
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " PXE Driver Downloader" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# --- Validate paths ---
$DeployPath = Join-Path $CachePath "Deploy"
$ControlPath = Join-Path $DeployPath "Control"
$ToolsPath = Join-Path (Split-Path $CachePath -Parent) "Tools"
if (-not (Test-Path $ToolsPath -PathType Container)) {
$ToolsPath = "C:\ProgramData\GEAerospace\MediaCreator\Tools"
}
if (-not (Test-Path $ControlPath -PathType Container)) {
Write-Host "ERROR: Deploy\Control not found at $ControlPath" -ForegroundColor Red
Write-Host " Run Media Creator Lite first to cache the base content." -ForegroundColor Yellow
exit 1
}
# --- Parse user_selections.json ---
$SelectionsFile = Join-Path $ToolsPath "user_selections.json"
if (-not (Test-Path $SelectionsFile)) {
Write-Host "ERROR: user_selections.json not found at $SelectionsFile" -ForegroundColor Red
exit 1
}
$selections = (Get-Content $SelectionsFile -Raw | ConvertFrom-Json)[0]
$selectedOsId = $selections.OperatingSystemSelection
$selectedModelIds = @($selections.HardwareModelSelection | ForEach-Object { $_.Id } | Select-Object -Unique)
# --- Parse HardwareDriver.json ---
$driverJsonFile = Join-Path $ControlPath "HardwareDriver.json"
if (-not (Test-Path $driverJsonFile)) {
Write-Host "ERROR: HardwareDriver.json not found in $ControlPath" -ForegroundColor Red
exit 1
}
$driverJson = Get-Content $driverJsonFile -Raw | ConvertFrom-Json
# --- Match drivers to selections ---
$matchedDrivers = @($driverJson | Where-Object {
$selectedModelIds -contains $_.family -and $_.aOsIds -contains $selectedOsId
})
# Deduplicate by DestinationDir (some models share a driver pack)
$uniqueDrivers = [ordered]@{}
foreach ($drv in $matchedDrivers) {
$rel = Resolve-DestDir $drv.DestinationDir
if (-not $uniqueDrivers.Contains($rel)) {
$uniqueDrivers[$rel] = $drv
}
}
$totalSize = [long]0
$uniqueDrivers.Values | ForEach-Object { $totalSize += $_.size }
# --- Display plan ---
Write-Host " Cache: $CachePath"
Write-Host " OS ID: $selectedOsId"
Write-Host " Models: $($selectedModelIds.Count) selected"
Write-Host " Drivers: $($uniqueDrivers.Count) unique pack(s) ($(Format-Size $totalSize))" -ForegroundColor Cyan
Write-Host ""
if ($uniqueDrivers.Count -eq 0) {
Write-Host "No drivers match your selections." -ForegroundColor Yellow
exit 0
}
# Show each driver pack
$idx = 0
foreach ($rel in $uniqueDrivers.Keys) {
$idx++
$drv = $uniqueDrivers[$rel]
$localDir = Join-Path $CachePath $rel
$cached = Test-Path $localDir -PathType Container
$status = if ($cached -and -not $Force) { "[CACHED]" } else { "[DOWNLOAD]" }
$color = if ($cached -and -not $Force) { "Green" } else { "Yellow" }
Write-Host (" {0,3}. {1,-12} {2} ({3})" -f $idx, $status, $drv.modelsfriendlyname, (Format-Size $drv.size)) -ForegroundColor $color
Write-Host " $($drv.FileName)" -ForegroundColor Gray
}
Write-Host ""
if ($ListOnly) {
Write-Host " (list only — run without -ListOnly to download)" -ForegroundColor Gray
exit 0
}
# --- Download and extract ---
$downloadDir = Join-Path $env:TEMP "PXE-DriverDownloads"
if (-not (Test-Path $downloadDir)) { New-Item -ItemType Directory -Path $downloadDir -Force | Out-Null }
$completed = 0
$skipped = 0
$errors = 0
foreach ($rel in $uniqueDrivers.Keys) {
$drv = $uniqueDrivers[$rel]
$localDir = Join-Path $CachePath $rel
$zipFile = Join-Path $downloadDir $drv.FileName
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "[$($completed + $skipped + $errors + 1)/$($uniqueDrivers.Count)] $($drv.modelsfriendlyname)" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
# Skip if already cached (unless -Force)
if ((Test-Path $localDir -PathType Container) -and -not $Force) {
Write-Host " Already cached at $rel" -ForegroundColor Green
$skipped++
Write-Host ""
continue
}
# Download
Write-Host " Downloading $(Format-Size $drv.size) ..." -ForegroundColor Gray
Write-Host " URL: $($drv.url)" -ForegroundColor DarkGray
try {
# Use curl.exe for progress display on large files
if (Get-Command curl.exe -ErrorAction SilentlyContinue) {
& curl.exe -L -o $zipFile $drv.url --progress-bar --fail
if ($LASTEXITCODE -ne 0) { throw "curl failed with exit code $LASTEXITCODE" }
} else {
# Fallback: WebClient (streams to disk, no buffering)
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($drv.url, $zipFile)
}
} catch {
Write-Host " ERROR: Download failed - $_" -ForegroundColor Red
$errors++
Write-Host ""
continue
}
# Verify SHA256 hash
Write-Host " Verifying SHA256 hash ..." -ForegroundColor Gray
$actualHash = (Get-FileHash -Path $zipFile -Algorithm SHA256).Hash
if ($actualHash -ne $drv.hash) {
Write-Host " ERROR: Hash mismatch!" -ForegroundColor Red
Write-Host " Expected: $($drv.hash)" -ForegroundColor Red
Write-Host " Got: $actualHash" -ForegroundColor Red
Remove-Item -Path $zipFile -Force -ErrorAction SilentlyContinue
$errors++
Write-Host ""
continue
}
Write-Host " Hash OK." -ForegroundColor Green
# Extract to cache destination
Write-Host " Extracting to $rel ..." -ForegroundColor Gray
if (Test-Path $localDir) { Remove-Item -Recurse -Force $localDir -ErrorAction SilentlyContinue }
New-Item -ItemType Directory -Path $localDir -Force | Out-Null
try {
Expand-Archive -Path $zipFile -DestinationPath $localDir -Force
} catch {
Write-Host " ERROR: Extraction failed - $_" -ForegroundColor Red
$errors++
Write-Host ""
continue
}
# Clean up zip
Remove-Item -Path $zipFile -Force -ErrorAction SilentlyContinue
Write-Host " Done." -ForegroundColor Green
$completed++
Write-Host ""
}
# --- Summary ---
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Download Summary" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Downloaded: $completed" -ForegroundColor Green
if ($skipped -gt 0) { Write-Host " Skipped: $skipped (already cached)" -ForegroundColor Gray }
if ($errors -gt 0) { Write-Host " Failed: $errors" -ForegroundColor Red }
Write-Host ""
if ($completed -gt 0 -or $skipped -gt 0) {
Write-Host "Driver packs are in the MCL cache at:" -ForegroundColor Cyan
Write-Host " $DeployPath\Out-of-box Drivers\" -ForegroundColor White
Write-Host ""
Write-Host "To upload to the PXE server:" -ForegroundColor Cyan
Write-Host " .\Upload-Image.ps1 -IncludeDrivers" -ForegroundColor White
Write-Host ""
}
# Clean up temp dir if empty
if ((Get-ChildItem $downloadDir -Force -ErrorAction SilentlyContinue | Measure-Object).Count -eq 0) {
Remove-Item $downloadDir -Force -ErrorAction SilentlyContinue
}