public/Update-OSDeployCoreDrivers.ps1

#Requires -PSEdition Core
#Requires -Version 7.4

function Update-OSDeployCoreDrivers {
    <#
    .SYNOPSIS
        Updates the WinPE driver catalog and matching driver packages
 
    .DESCRIPTION
        Refreshes the requested WinPE driver catalog sources, then delegates matching package
        processing to Save-WinPEDriverPackageCore. Without Name, processes all refreshable
        catalog sources and all matching packages. The command does not display a package
        selection prompt.
 
        Package handlers store downloads under the OSDeploy Core download cache and normally
        expand driver content into boot-assets\winpedrivers-amd64 or
        boot-assets\winpedrivers-arm64. Successfully processed package files returned by
        Save-WinPEDriverPackageCore are passed through. Catalog output is suppressed.
 
    .PARAMETER Name
        Specifies one or more configured catalog source identifiers to refresh and process.
        This is positional parameter 0. When omitted, all refreshable sources are processed.
        Unknown or nonrefreshable names are reported and skipped.
 
    .PARAMETER Force
        Passes Force to catalog refresh and package handlers so they refresh content instead
        of relying on current catalog or download-cache state.
 
    .PARAMETER SkipWifiDrivers
        Excludes matching packages whose names contain wifi or wireless. When no imported
        Windows RE sources are found, the command enables this behavior automatically and
        writes a warning because ADK WinPE does not support wireless hardware.
 
    .PARAMETER DownloadOnly
        Passes DownloadOnly to package handlers. Downloads are retained in the OSDeploy Core
        download cache, expansion is skipped, and Save-WinPEDriverPackageCore does not write
        package.json metadata.
 
    .PARAMETER Architecture
        Limits package processing to amd64 or arm64. Packages with no architecture value also
        remain eligible. Catalog refresh is not filtered by this parameter.
 
    .EXAMPLE
        PS> Update-OSDeployCoreDrivers -Name 'dell'
 
        Refreshes the dell catalog and downloads all matching dell packages.
 
    .EXAMPLE
        PS> Update-OSDeployCoreDrivers -Name 'dell', 'hp' -WhatIf
 
        Shows the catalog refresh and download actions for dell and hp without executing them.
 
    .EXAMPLE
        PS> Update-OSDeployCoreDrivers -Name 'dell' -DownloadOnly
 
        Refreshes the dell catalog and downloads the .cab without expanding it.
 
    .EXAMPLE
        PS> Update-OSDeployCoreDrivers -SkipWifiDrivers
 
        Refreshes all configured sources, excludes Wi-Fi packages, and downloads all remaining packages.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        System.IO.FileInfo. Returns package files emitted by Save-WinPEDriverPackageCore for
        successfully processed matching packages. Returns no catalog file object.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 1.0.0
        Date: 2026-08-28
 
        Requires Windows 11 25H2 or later, PowerShell 7.4 or later installed from MSI,
        curl.exe, and Administrator rights.
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    [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 -not $_.Value.Disabled -and $_.Name -like "$wordToComplete*" } |
                ForEach-Object { [System.Management.Automation.CompletionResult]::new($_.Name) }
        })]
        [string[]]$Name,

        [Parameter()]
        [switch]$Force,

        [Parameter()]
        [switch]$SkipWifiDrivers,

        [Parameter()]
        [switch]$DownloadOnly,

        [Parameter()]
        [ValidateSet('amd64', 'arm64')]
        [System.String]
        $Architecture
    )

    begin {
        #=================================================
        Write-HostOSDeployBanner
        #=================================================
        # Require License for this function. If the license is not valid, return without executing the function.
        if (-not (Test-OSDeployLicenseGate -CommandName $MyInvocation.MyCommand.Name)) {
            return
        }
        #=================================================
        # Stop before refreshing driver content when a required host capability is missing.
        if (-not (Test-IsWindows11)) {
            throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Windows 11 is required."
        }
        if (-not (Test-IsWindows1125H2)) {
            throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Windows 11 25H2 (build 26200) is required."
        }
        if (-not (Test-PwshVersionMin)) {
            throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] PowerShell 7.4 or higher is required."
        }
        if (-not (Test-PwshPSHome)) {
            throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] The MSI installation of PowerShell 7 is required."
        }
        if (-not (Test-CommandCurl)) {
            throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] curl.exe is required but was not found in the current PATH. curl.exe ships with Windows 10 1803+."
        }
        if (-not (Test-IsAdministrator)) {
            throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Administrator rights are required. Re-run PowerShell as Administrator and try again."
        }
        #=================================================
        Initialize-OSDeployCorePaths
        #=================================================

        # Skip Wi-Fi packages when no WinRE source can support them.
        if (-not $SkipWifiDrivers) {
            $importedSources = Get-OSDeployCoreWindowsRE -ErrorAction SilentlyContinue
            if (-not $importedSources) {
                $SkipWifiDrivers = $true
                Write-Warning "[$(Get-Date -Format s)] No imported OS sources found. Wi-Fi drivers require WinRE (ADK WinPE does not support wireless hardware) and will be skipped."
            }
        }
    }

    process {
        $targetLabel = if ($Name) {
            $Name -join ', '
        }
        else {
            'all refreshable sources'
        }

        $commonParameters = @{ Confirm = $false }
        # Forward WhatIf to child commands so their planned actions remain visible.
        if ($WhatIfPreference) {
            $commonParameters.WhatIf = $true
        }

        $catalogParameters = @{}
        if ($Name) {
            $catalogParameters.Name = $Name
        }
        if ($Force) {
            $catalogParameters.Force = $true
        }

        $saveParameters = @{ SkipCatalogRefresh = $true; Confirm = $false }
        if ($Name) {
            $saveParameters.Name = $Name
        }
        if ($Force) {
            $saveParameters.Force = $true
        }
        if ($SkipWifiDrivers) {
            $saveParameters.SkipWifiDrivers = $true
        }
        if ($DownloadOnly) {
            $saveParameters.DownloadOnly = $true
        }
        if ($Architecture) {
            $saveParameters.Architecture = $Architecture
        }
        if ($WhatIfPreference) {
            $saveParameters.WhatIf = $true
        }

        if ($WhatIfPreference) {
            Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] WhatIf: Refreshing WinPE driver catalog for: $targetLabel"
            Update-OSDeployCoreDriversCatalog @catalogParameters @commonParameters | Out-Null
            Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] WhatIf: Downloading and expanding WinPE driver packages ..."
            Save-WinPEDriverPackageCore @saveParameters
            return
        }

        # Honor WhatIf and Confirm before refreshing catalogs and changing the managed driver library.
        if ($PSCmdlet.ShouldProcess($targetLabel, 'Refresh catalog and save WinPE drivers for BootMedia')) {
            Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Refreshing WinPE driver catalog for: $targetLabel"
            Update-OSDeployCoreDriversCatalog @catalogParameters @commonParameters | Out-Null

            Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Downloading and expanding WinPE driver packages ..."
            $driverResults = @(Save-WinPEDriverPackageCore @saveParameters)

            $downloadedCount = ($driverResults | Where-Object { $_ }).Count
            Write-HostDateTimeDarkCyan "[$($MyInvocation.MyCommand.Name)] Done. $downloadedCount driver package(s) processed."
            $driverResults
        }
    }

    end {
        # Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] [INFO] Stop"
    }
}