private/WinPEDrivers/CloudWinPEDriver/Save-CloudWinPEDriver.ps1
|
#Requires -PSEdition Core function Save-CloudWinPEDriver { <# .SYNOPSIS Internal helper that selects and downloads WinPE driver packages to $env:ProgramData\OSDeployCore. .DESCRIPTION Internal helper used by Update-OSDeployWinPEDrivers. It resolves available WinPE driver packages (from Get-CloudWinPEDriver) and by default processes all matching packages directly. When -Interactive is specified, an Out-GridView is displayed showing Architecture, Version, download status, and expansion status for each entry, and the user selects which packages to process before any download begins. Downloads are delegated to per-driver private functions (Save-CloudWinPEDriver{Name}) that handle the specific download and expansion logic for each vendor. A JSON metadata file is written to $env:ProgramData\OSDeployCore\Repository\winpe-drivers\{Architecture}\{Name}-{Version}\package.json after each successful download. When -Interactive is not specified, all matching packages are processed directly and Out-GridView is not used. .PARAMETER Name One or more source names to download. Tab-completion excludes Disabled sources. When omitted, all non-Disabled sources are presented in the GridView. .PARAMETER DriverPackage A OSDeployWinPEDriver.Package object from Get-CloudWinPEDriver. Bypasses the GridView. .PARAMETER Force Re-download even if the file already exists and the checksum matches. .PARAMETER SkipCatalogRefresh Internal switch used when the caller already refreshed the requested catalog entries. .PARAMETER SkipWifiDrivers Exclude Wi-Fi driver packages (sources whose name matches 'wifi' or 'wireless') from download and processing. Automatically set when no imported OS sources are present, because ADK WinPE does not support wireless hardware. .PARAMETER Interactive Internal switch used by Update-OSDeployWinPEDrivers to open the Out-GridView picker so the user can select which packages to download. .OUTPUTS [System.IO.FileInfo] The downloaded file(s). .NOTES Author: David Segura Version: 0.1.0 #> [CmdletBinding( SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ByName' )] [OutputType([System.IO.FileInfo])] param ( [Parameter( Position = 0, ParameterSetName = 'ByName', HelpMessage = 'Source name to download.' )] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $global:OSDeployModule.WinPEDrivers.PSObject.Properties | Where-Object { ($_.Value.UpdateUri -or $_.Value.DownloadUri) -and -not $_.Value.Disabled -and $_.Name -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_.Name) } })] [string[]]$Name, [Parameter( Mandatory, ValueFromPipeline, ParameterSetName = 'ByPipeline' )] [PSTypeName('OSDeployWinPEDriver.Package')] [PSCustomObject]$DriverPackage, [Parameter()] [switch]$Force, [Parameter()] [switch]$DownloadOnly, [Parameter(ParameterSetName = 'ByName')] [switch]$SkipCatalogRefresh, [Parameter(ParameterSetName = 'ByName')] [switch]$SkipWifiDrivers, [Parameter(ParameterSetName = 'ByName')] [switch]$Interactive ) begin { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Starting" $currentPrincipal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent() if (-not $WhatIfPreference -and -not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.UnauthorizedAccessException]::new('Update-OSDeployWinPEDrivers requires an elevated (Administrator) PowerShell session to save driver content.'), 'ElevationRequired', [System.Management.Automation.ErrorCategory]::PermissionDenied, $null ) ) } } process { $packages = if ($PSCmdlet.ParameterSetName -eq 'ByName') { $candidates = if ($Name) { Get-CloudWinPEDriver -Name $Name -SkipCatalogRefresh:$SkipCatalogRefresh } else { Get-CloudWinPEDriver -SkipCatalogRefresh:$SkipCatalogRefresh } if ($SkipWifiDrivers) { $candidates = $candidates | Where-Object { $_.Name -notmatch 'wifi|wireless' } } $gridItems = $candidates | ForEach-Object { $pkg = $_ $idPrefix = ($pkg.Name -split '-')[0] $downloadPath = Join-Path (Join-Path $script:OSDeployCoreDownloadsPath $idPrefix) $pkg.FileName if ($null -eq $pkg.Version) { $pkg.Version = $pkg.PackageId } $expandDir = Join-Path $script:OSDeployCoreRepositoryPath 'winpe-drivers' | Join-Path -ChildPath $pkg.Architecture | Join-Path -ChildPath "$($pkg.Name)-$($pkg.Version)" [PSCustomObject]@{ Id = $pkg.Id Architecture = $pkg.Architecture ReleaseDate = $pkg.ReleaseDate Version = $pkg.Version FileName = $pkg.FileName FileSizeMB = $pkg.FileSizeMB DownloadUri = $pkg.DownloadUri ExpandedPath = $expandDir Name = "$($pkg.Name)-$($pkg.Version)" Downloaded = (Test-Path -Path $downloadPath) ? 'Yes' : 'No' Expanded = (Get-ChildItem -Path $expandDir -Recurse -File -ErrorAction SilentlyContinue | Select-Object -First 1) ? 'Yes' : 'No' } } if ($Interactive) { $upToDate = $gridItems | Where-Object { $_.Downloaded -eq 'Yes' -and $_.Expanded -eq 'Yes' } $needsAction = $gridItems | Where-Object { $_.Downloaded -ne 'Yes' -or $_.Expanded -ne 'Yes' } foreach ($item in $upToDate) { Write-OSDeployWinPEDriversProgress "Complete: $($item.Name)" } $downloadsPath = $script:OSDeployCoreDownloadsPath if (Test-Path -Path $downloadsPath) { $downloadsSizeBytes = (Get-ChildItem -Path $downloadsPath -Recurse -File -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum $downloadsSizeGB = [math]::Round($downloadsSizeBytes / 1GB, 1) Write-OSDeployWinPEDriversProgress "$downloadsPath is currently using $downloadsSizeGB GB" } if (-not $needsAction) { Write-OSDeployWinPEDriversProgress "All driver packages are downloaded, expanded, and up to date." return } # Write-OSDeployWinPEDriversProgress "Select Drivers in GridView to download and expand" # Write-OSDeployWinPEDriversProgress "Downloads are saved to $($Script:OSDeployCorePath)\cache\downloads" # Write-OSDeployWinPEDriversProgress "Expanded content is saved to $($script:OSDeployCoreRepositoryPath)\winpe-drivers" $selected = $needsAction | Select-Object -Property Id, Name, Architecture, ReleaseDate, Version, FileSizeMB, DownloadUri | Out-GridView -Title "[$(Get-Date -format s)] OSDeployCore: Select winpe driver packages to add to the Library $($Script:OSDeployCorePath)" -PassThru if (-not $selected) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No drivers selected." return } $selectedKeys = $selected | ForEach-Object { $_.Name } $candidates | Where-Object { "$($_.Name)-$($_.Version)" -in $selectedKeys } } else { if (-not $candidates) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No matching drivers found for processing." return } Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Processing all matching packages without Out-GridView" $candidates } } else { $DriverPackage } foreach ($package in $packages) { if ([string]::IsNullOrWhiteSpace($package.DownloadUri)) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No DownloadUri for '$($package.Name)'. Skipping." continue } $action = "Download '$($package.FileName)'" if (-not $PSCmdlet.ShouldProcess($package.DownloadUri, $action)) { continue } $downloadedFile = switch -Wildcard ($package.Name) { 'intel-ethernet' { Save-CloudWinPEDriverIntelEthernet -DriverPackage $package -Force:$Force -DownloadOnly:$DownloadOnly } 'intel-wifi' { Save-CloudWinPEDriverIntelWifi -DriverPackage $package -Force:$Force -DownloadOnly:$DownloadOnly } 'microsoft-windows-ethernet' { Save-CloudWinPEDriverWindowsEthernet -DriverPackage $package -Force:$Force -DownloadOnly:$DownloadOnly } 'microsoft-windows-wifi' { Save-CloudWinPEDriverWindowsWifi -DriverPackage $package -Force:$Force -DownloadOnly:$DownloadOnly } 'dell' { Save-CloudWinPEDriverOemDell -DriverPackage $package -Force:$Force -DownloadOnly:$DownloadOnly } 'hp' { Save-CloudWinPEDriverOemHp -DriverPackage $package -Force:$Force -DownloadOnly:$DownloadOnly } 'vmware' { Save-CloudWinPEDriverOemVMwareAMD64 -DriverPackage $package -Force:$Force -DownloadOnly:$DownloadOnly } 'vmware-arm64' { Save-CloudWinPEDriverOemVMwareARM64 -DriverPackage $package -Force:$Force -DownloadOnly:$DownloadOnly } default { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No save function registered for '$($package.Name)'. Skipping." $null } } if (-not $downloadedFile) { continue } if ($DownloadOnly) { $downloadedFile continue } $arch = if ([string]::IsNullOrWhiteSpace($package.Architecture)) { 'amd64' } else { $package.Architecture } $version = if ([string]::IsNullOrWhiteSpace($package.Version)) { $package.PackageId } else { $package.Version } $finalDriverPath = Join-Path $script:OSDeployCoreRepositoryPath 'winpe-drivers' | Join-Path -ChildPath $arch | Join-Path -ChildPath "$($package.Name)-$version" $jsonPath = Join-Path $script:OSDeployCoreRepositoryPath 'winpe-drivers' | Join-Path -ChildPath $arch | Join-Path -ChildPath "$($package.Name)-$version" | Join-Path -ChildPath 'package.json' Write-OSDeployWinPEDriversProgress -Message "$jsonPath" if (-not (Test-Path -Path $jsonPath)) { $jsonDir = Split-Path -Path $jsonPath -Parent if (-not (Test-Path -Path $jsonDir)) { New-Item -ItemType Directory -Path $jsonDir -Force | Out-Null } $metadata = [ordered]@{ Name = $package.Name Architecture = $arch Id = $package.Id PackageId = $package.PackageId Version = $package.Version ReleaseDate = $package.ReleaseDate FileName = $package.FileName FileSizeMB = $package.FileSizeMB DownloadUri = $package.DownloadUri ExpandCommand = $package.ExpandCommand Checksums = $package.Checksums DownloadedOn = (Get-Date -Format 'yyyy-MM-dd') } try { $metadata | ConvertTo-Json -Depth 5 | Set-Content -Path $jsonPath -Encoding UTF8 -ErrorAction Stop Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Metadata written to '$jsonPath'" } catch { Write-Error "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Failed to write package.json: $($_.Exception.Message)" } } $downloadedFile } } end { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Complete" } } |