# # 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 }