private/WinPEDrivers/Update-OSDeployWinPEDriversCatalog.ps1
|
#Requires -PSEdition Core function Update-OSDeployWinPEDriversCatalog { <# .SYNOPSIS Discovers the latest WinPE driver pack metadata and writes a local catalog file. .DESCRIPTION Iterates over active sources defined in winpedrivers.json and writes the results to $env:ProgramData\OSDeployCore\cache\config\winpedrivers.json. Dynamic sources (those with an UpdateUri property) are resolved by calling the appropriate per-vendor discovery function. Static sources (those with a DownloadUri property) are copied directly from winpedrivers.json. When -Name is specified, only those sources are refreshed; all other sources already in the catalog are preserved unchanged (merge behaviour). If a vendor page cannot be reached or parsed, a warning is emitted and that source is skipped — the rest of the catalog is still updated. .PARAMETER Name One or more source names to refresh. Tab-completion is supported. When omitted, all active sources are written. .PARAMETER Force Overwrite the catalog even if the CatalogDate is already today. .EXAMPLE PS> Update-OSDeployWinPEDriversCatalog Refreshes all configured sources and writes the catalog to $env:ProgramData\OSDeployCore\cache\config\winpedrivers.json. .EXAMPLE PS> Update-OSDeployWinPEDriversCatalog -Name 'dell' Refreshes only the dell entry, preserving all other catalog entries. .EXAMPLE PS> Update-OSDeployWinPEDriversCatalog -Name 'dell', 'hp' -Verbose Refreshes dell and hp with verbose progress output. .OUTPUTS [System.IO.FileInfo] The written catalog file. .NOTES Author: David Segura Version: 0.1.0 #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([System.IO.FileInfo])] param ( [Parameter(Position = 0)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $global:OSDeployModule.WinPEDrivers.PSObject.Properties | Where-Object { ($_.Value.UpdateUri -or $_.Value.DownloadUri) -and $_.Name -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_.Name) } })] [string[]]$Name, [Parameter()] [switch]$Force ) begin { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Starting" Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] OSDeployWinPEDriversUserConfig='$Script:OSDeployWinPEDriversUserConfig'" Write-OSDeployWinPEDriversProgress "Checking for updated WinPE drivers ..." } process { # Determine which source names can be written to the catalog. $allRefreshable = @( $global:OSDeployModule.WinPEDrivers.PSObject.Properties | Where-Object { $_.Value.UpdateUri -or $_.Value.DownloadUri } | Select-Object -ExpandProperty Name ) Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Active sources defined in winpedrivers.json: $($allRefreshable -join ', ')" $targetNames = if ($Name) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] -Name specified — filtering to: $($Name -join ', ')" $Name | Where-Object { if ($_ -notin $allRefreshable) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] '$_' is not a refreshable source. Skipping." $false } else { $true } } } else { $allRefreshable } Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Sources to refresh: $($targetNames -join ', ')" if (-not $targetNames) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No valid sources to refresh." return } # Load existing catalog for merge (or create empty shell) $catalog = if (Test-Path -Path $Script:OSDeployWinPEDriversUserConfig) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Existing catalog found — loading for merge" Get-Content -Path $Script:OSDeployWinPEDriversUserConfig -Raw | ConvertFrom-Json } else { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No existing catalog — starting with empty shell" [PSCustomObject]@{ CatalogDate = '' Sources = [PSCustomObject]@{} } } # Map Dynamic source name → discovery function name $parserMap = @{ 'intel-ethernet' = 'Get-CloudWinPEDriverIntelEthernet' 'intel-wifi' = 'Get-CloudWinPEDriverIntelWifi' 'dell' = 'Get-CloudWinPEDriverOemDell' 'hp' = 'Get-CloudWinPEDriverOemHp' 'vmware' = 'Get-CloudWinPEDriverOemVMware' 'vmware-arm64' = 'Get-CloudWinPEDriverOemVMware' } foreach ($n in $targetNames) { $sourceData = $global:OSDeployModule.WinPEDrivers.$n $isDynamic = [bool]$sourceData.UpdateUri $parserFn = $parserMap[$n] try { $info = if (-not $isDynamic) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Copying static metadata for '$n' from winpedrivers.json" [PSCustomObject]@{ Architecture = $sourceData.Architecture ReadmeUri = $null PackageId = $sourceData.PackageId Version = $null ReleaseDate = $null FileName = $sourceData.FileName FileSizeMB = $sourceData.FileSizeMB DownloadUri = $sourceData.DownloadUri Checksums = [PSCustomObject]@{} } } else { if (-not $parserFn) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No discovery function registered for '$n'. Skipping." continue } Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Discovering '$n' via $parserFn" $raw = & $parserFn # VMware returns both architectures — filter to the one matching this source $arch = $sourceData.Architecture if (@($raw).Count -gt 1) { $raw | Where-Object { $_.Architecture -eq $arch } | Select-Object -First 1 } else { $raw } } if ($null -eq $info) { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] '$n' returned no data. Existing catalog entry preserved." continue } Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] '$n' — Architecture='$($info.Architecture)' PackageId='$($info.PackageId)' Version='$($info.Version)' ReleaseDate='$($info.ReleaseDate)' FileName='$($info.FileName)'" # Store as a single object per source $catalog.Sources | Add-Member -MemberType NoteProperty -Name $n -Value $info -Force Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] '$n' updated successfully." } catch { Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] '$n' discovery failed — $($_.Exception.Message). Existing catalog entry preserved." } } $catalog.CatalogDate = Get-Date -Format 'yyyy-MM-dd' Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Setting CatalogDate='$($catalog.CatalogDate)'" # Write catalog $catalogDir = Split-Path -Path $Script:OSDeployWinPEDriversUserConfig -Parent if (-not (Test-Path -Path $catalogDir)) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Creating catalog directory '$catalogDir'" New-Item -ItemType Directory -Path $catalogDir -Force | Out-Null } if ($PSCmdlet.ShouldProcess($Script:OSDeployWinPEDriversUserConfig, 'Write WinPE driver catalog')) { $catalog | ConvertTo-Json -Depth 10 | Set-Content -Path $Script:OSDeployWinPEDriversUserConfig -Encoding UTF8 -ErrorAction Stop Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Catalog written to '$Script:OSDeployWinPEDriversUserConfig'" } Get-Item -Path $Script:OSDeployWinPEDriversUserConfig } end { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Complete" } } |