private/Update-OSDeployCoreDriversCatalog.ps1
|
#Requires -PSEdition Core function Update-OSDeployCoreDriversCatalog { <# .SYNOPSIS Updates the local WinPE driver catalog .DESCRIPTION Reads refreshable WinPE driver sources from $global:OSDeployModule.WinPEDrivers. Sources with an UpdateUri are resolved by a vendor-specific discovery function. Sources with only a DownloadUri use the static metadata in the module configuration. When Name is omitted, the function processes every source that has an UpdateUri or DownloadUri. When Name is specified, it processes only valid matching sources. Existing entries for sources that are not processed, return no data, or fail discovery are preserved. The function sets CatalogDate to the current date and writes the merged catalog to $Script:OSDeployWinPEDriversUserConfig. ShouldProcess gates the catalog write, but creation of its parent directory occurs before that gate. Discovery failures generate warnings and do not stop the remaining sources from being processed. .PARAMETER Name Specifies one or more source names to process. Position 0 is supported. The argument completer suggests configured sources that have an UpdateUri or DownloadUri. Invalid or non-refreshable names generate warnings and are skipped. .PARAMETER Force This switch is accepted for compatibility but currently does not alter the function's behavior. .EXAMPLE PS> Update-OSDeployCoreDriversCatalog Processes every refreshable source and writes the merged catalog. .EXAMPLE PS> Update-OSDeployCoreDriversCatalog -Name 'dell', 'hp' -Verbose Processes the dell and hp sources while displaying verbose discovery details. .EXAMPLE PS> Update-OSDeployCoreDriversCatalog -Name 'dell' -WhatIf Discovers the dell metadata and shows the catalog write without performing it. The parent catalog directory can still be created. .INPUTS None. This function does not accept pipeline input. .OUTPUTS System.IO.FileInfo. Returns the catalog file when the configured path exists. .NOTES Author: David Segura Company: Recast Software Version: 0.1.0 Date: 2026-08-28 Requires PowerShell Core and initialized $global:OSDeployModule.WinPEDrivers and $Script:OSDeployWinPEDriversUserConfig values. Dynamic sources require access to their vendor metadata endpoints. #> [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 "[$($MyInvocation.MyCommand.Name)] Starting" Write-Verbose "[$($MyInvocation.MyCommand.Name)] OSDeployWinPEDriversUserConfig='$Script:OSDeployWinPEDriversUserConfig'" Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] 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 "[$($MyInvocation.MyCommand.Name)] Active sources defined in winpedrivers.json: $($allRefreshable -join ', ')" $targetNames = if ($Name) { Write-Verbose "[$($MyInvocation.MyCommand.Name)] -Name specified — filtering to: $($Name -join ', ')" $Name | Where-Object { if ($_ -notin $allRefreshable) { Write-Warning "[$(Get-Date -Format s)] '$_' is not a refreshable source. Skipping." $false } else { $true } } } else { $allRefreshable } Write-Verbose "[$($MyInvocation.MyCommand.Name)] Sources to refresh: $($targetNames -join ', ')" if (-not $targetNames) { Write-Warning "[$(Get-Date -Format s)] No valid sources to refresh." return } # Load existing catalog for merge (or create empty shell) $catalog = if (Test-Path -Path $Script:OSDeployWinPEDriversUserConfig) { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Existing catalog found — loading for merge" Get-Content -Path $Script:OSDeployWinPEDriversUserConfig -Raw | ConvertFrom-Json } else { Write-Verbose "[$($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-WinPEDriverPackageIntelEthernet' 'intel-wifi' = 'Get-WinPEDriverPackageIntelWifi' 'dell' = 'Get-WinPEDriverPackageDell' 'hp' = 'Get-WinPEDriverPackageHp' 'vmware' = 'Get-WinPEDriverPackageVMware' 'vmware-arm64' = 'Get-WinPEDriverPackageVMware' } foreach ($n in $targetNames) { $sourceData = $global:OSDeployModule.WinPEDrivers.$n $isDynamic = [bool]$sourceData.UpdateUri $parserFn = $parserMap[$n] try { $info = if (-not $isDynamic) { Write-Verbose "[$($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)] No discovery function registered for '$n'. Skipping." continue } Write-Verbose "[$($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)] '$n' returned no data. Existing catalog entry preserved." continue } Write-Verbose "[$($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 "[$($MyInvocation.MyCommand.Name)] '$n' updated successfully." } catch { Write-Warning "[$(Get-Date -Format s)] '$n' discovery failed — $($_.Exception.Message). Existing catalog entry preserved." } } $catalog.CatalogDate = Get-Date -Format 'yyyy-MM-dd' Write-Verbose "[$($MyInvocation.MyCommand.Name)] Setting CatalogDate='$($catalog.CatalogDate)'" # Write catalog $catalogDir = Split-Path -Path $Script:OSDeployWinPEDriversUserConfig -Parent if (-not (Test-Path -Path $catalogDir)) { Write-Verbose "[$($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 "[$($MyInvocation.MyCommand.Name)] Catalog written to '$Script:OSDeployWinPEDriversUserConfig'" } Get-Item -Path $Script:OSDeployWinPEDriversUserConfig } end { Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete" } } |