private/Step-BuildBootCoreWinPEDrivers.ps1

#Requires -PSEdition Core

function Step-BuildBootCoreWinPEDrivers {
    <#
    .SYNOPSIS
        Adds configured and profile-local drivers to the mounted WinPE image
 
    .DESCRIPTION
        Adds driver paths from global BuildMedia.WinPEDriver, followed by the build
        profile's architecture-matched winpedrivers-amd64 or winpedrivers-arm64 directory
        when that directory contains an INF file. Paths are processed in configured-first
        order, and duplicate paths are added only once.
 
        Existing paths are passed to Add-WindowsDriver with recursive and unsigned
        driver support. A timestamped DISM log is written for each path. Missing paths
        produce warnings, and installation failures write non-terminating errors.
 
    .EXAMPLE
        PS> Step-BuildBootCoreWinPEDrivers
 
        Adds the configured and profile-local driver trees to the mounted image.
 
    .INPUTS
        None. This function does not accept pipeline input.
 
    .OUTPUTS
        None.
 
    .NOTES
        Author: David Segura
        Company: Recast Software
        Version: 0.1.0
        Date: 2026-08-28
 
        Requires global BuildMedia with MountPath, LogsPath, WinPEDriver, and
        BuildProfile properties. BuildProfileContentPath optionally overrides the
        profile-local content directory. Requires Add-WindowsDriver and write access
        to the mounted image and log directory.
    #>

    [CmdletBinding()]
    param ()

    $MountPath = $global:BuildMedia.MountPath
    $WinPEDriver = @($global:BuildMedia.WinPEDriver | Where-Object { $_ })
    $LogsPath = $global:BuildMedia.LogsPath
    $BuildProfilePath = $global:BuildMedia.BuildProfile
    $BuildProfileContentPath = $global:BuildMedia.BuildProfileContentPath
    if (-not $BuildProfileContentPath -and $BuildProfilePath) {
        $BuildProfileContentPath = Split-Path -Path $BuildProfilePath -Parent
    }
    $Architecture = $global:BuildMedia.Architecture
    $ProfileDriverPath = if ($BuildProfileContentPath -and $Architecture -in @('amd64', 'arm64')) {
        Join-Path $BuildProfileContentPath "winpedrivers-$Architecture"
    }

    # Add the flat profile-local driver root once when it contains at least one INF.
    if ($ProfileDriverPath -and (Test-Path -LiteralPath $ProfileDriverPath -PathType Container)) {
        $ProfileDriverInf = Get-ChildItem -LiteralPath $ProfileDriverPath -Filter '*.inf' -File -Recurse -ErrorAction SilentlyContinue |
            Select-Object -First 1
        if ($ProfileDriverInf) {
            $WinPEDriver += $ProfileDriverPath
        }
    }

    # Preserve configured-first order while preventing duplicate driver paths.
    $SeenDrivers = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
    $WinPEDriver = @($WinPEDriver | Where-Object { $SeenDrivers.Add([System.String]$_) })

    if ($WinPEDriver) {
        Write-HostDateTimeDarkGray 'WinPEDriver: Add-WindowsDriver'
        foreach ($DriverPath in $WinPEDriver) {
            if (Test-Path -LiteralPath $DriverPath) {
                Write-Host -ForegroundColor DarkGray "$DriverPath"
                $CurrentLog = "$LogsPath\$((Get-Date).ToString('yyMMdd-HHmmss'))-Add-WindowsDriver.log"
                try {
                    $null = Add-WindowsDriver -Path $MountPath -Driver $DriverPath -ForceUnsigned -Recurse -LogPath "$CurrentLog" -ErrorAction Stop
                }
                catch {
                    Write-Error "Driver failed to install from: $DriverPath"
                    Write-Error "Dism Log: $CurrentLog"
                }
            }
            else {
                Write-Warning "[$(Get-Date -Format s)] WinPEDriver not found: $DriverPath"
            }
        }
    }
}