Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 156 additions & 16 deletions functions/private/Invoke-WinUtilISOScript.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,130 @@ function Invoke-WinUtilISOScript {
}
}

function Test-WinUtilISODriverExtensionClass {
param ([Parameter(Mandatory)][System.IO.FileInfo]$InfFile)

try {
return (Get-Content -LiteralPath $InfFile.FullName -Raw -ErrorAction Stop) -match '(?im)^\s*Class\s*=\s*Extension\s*(?:;.*)?$'
Comment thread
mewclouds marked this conversation as resolved.
Outdated
} catch {
& $Logger "Warning: could not classify driver '$($InfFile.FullName)': $_"
return $false
}
}

function Get-WinUtilISODriverPackageVersion {
param ([Parameter(Mandatory)][System.IO.FileInfo]$InfFile)

try {
$infText = Get-Content -LiteralPath $InfFile.FullName -Raw -ErrorAction Stop
} catch {
& $Logger "Warning: could not read '$($InfFile.FullName)' to determine its driver version: $_"
return $null
}

# The version component of DriverVer is optional per the INF spec (date-only entries
# are valid); treat a missing version as 0.0 so date-only entries still rank correctly
# instead of being discarded as unparseable.
$match = [regex]::Match($infText, '(?im)^\s*DriverVer\s*=\s*(?<date>\d{1,2}/\d{1,2}/\d{4})\s*(?:,\s*(?<version>\d+(?:\.\d+){0,3}))?\s*(?:;.*)?$')
if (-not $match.Success) {
return $null
}

try {
$date = [datetime]::ParseExact($match.Groups['date'].Value, 'M/d/yyyy', [System.Globalization.CultureInfo]::InvariantCulture)
$versionText = if ($match.Groups['version'].Success) { $match.Groups['version'].Value } else { '0' }
if (($versionText.Split('.')).Count -lt 2) {
$versionText = "$versionText.0"
}
$version = [version]$versionText
} catch {
& $Logger "Warning: could not parse DriverVer '$($match.Value.Trim())' in '$($InfFile.FullName)': $_"
return $null
}

return [pscustomobject]@{
Date = $date
Version = $version
Raw = if ($match.Groups['version'].Success) { "$($match.Groups['date'].Value),$($match.Groups['version'].Value)" } else { $match.Groups['date'].Value }
}
}

function Select-WinUtilISOStagedDriverPackages {
param (
[Parameter(Mandatory)][AllowEmptyCollection()][object[]]$DriverFolderGroups,
[scriptblock]$Logger
)

$survivingFolders = [System.Collections.Generic.List[string]]::new()
$dedupGroups = @{}

foreach ($driverFolderGroup in $DriverFolderGroups) {
$driverFolder = [string]$driverFolderGroup.Name
$isExtension = [bool]@($driverFolderGroup.Group | Where-Object { Test-WinUtilISODriverExtensionClass -InfFile $_ }).Count
Comment thread
mewclouds marked this conversation as resolved.

if ($isExtension) {
# $null = discards $Logger's own output; this function's return value is captured
# by the caller, and an emitting logger (e.g. this function's own default) would
# otherwise leak into the surviving-folder list.
$null = & $Logger "Excluding extension-class driver package '$driverFolder' from Add-Driver (Class=Extension is not a serviceable hardware driver)."
continue
Comment thread
mewclouds marked this conversation as resolved.
}

# DISM names exported package folders <infname>_<arch>_<hash>; grouping on infname+arch
# (dropping the hash) is what lets us recognize two exports of the same driver. When a
# folder doesn't match that pattern, fall back to the full path rather than the leaf name:
# two unrelated folders at different depths (e.g. group_a\duplicate and group_b\duplicate)
# can share a leaf name, and the full path is guaranteed unique per group.
$leafName = Split-Path -Path $driverFolder -Leaf
$dedupKey = $driverFolder
$nameMatch = [regex]::Match($leafName, '(?i)^(?<infname>.+)_(?<arch>x86|amd64|arm64|arm|wow)_[0-9a-f]{16}$')
if ($nameMatch.Success) {
$dedupKey = "$($nameMatch.Groups['infname'].Value.ToLowerInvariant())_$($nameMatch.Groups['arch'].Value.ToLowerInvariant())"
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
mewclouds marked this conversation as resolved.

if (-not $dedupGroups.ContainsKey($dedupKey)) {
$dedupGroups[$dedupKey] = [System.Collections.Generic.List[object]]::new()
}
$dedupGroups[$dedupKey].Add($driverFolderGroup)
}

foreach ($dedupKey in $dedupGroups.Keys) {
$candidates = $dedupGroups[$dedupKey]
if ($candidates.Count -eq 1) {
$survivingFolders.Add([string]$candidates[0].Name)
continue
}

$ranked = @($candidates | ForEach-Object {
$primaryVersion = ($_.Group | ForEach-Object { Get-WinUtilISODriverPackageVersion -InfFile $_ } | Where-Object { $_ }) |
Sort-Object -Property Date, Version -Descending | Select-Object -First 1
[pscustomobject]@{ Folder = [string]$_.Name; Version = $primaryVersion }
})

$withVersion = @($ranked | Where-Object { $_.Version })
if ($withVersion.Count -eq 0) {
$null = & $Logger "Warning: could not determine DriverVer for any duplicate of '$dedupKey'; keeping all $($ranked.Count) package(s) rather than guessing."
foreach ($candidate in $ranked) {
$survivingFolders.Add($candidate.Folder)
}
continue
}

$kept = $withVersion | Sort-Object -Property @{ Expression = { $_.Version.Date } }, @{ Expression = { $_.Version.Version } } -Descending | Select-Object -First 1
$survivingFolders.Add($kept.Folder)

foreach ($candidate in $ranked) {
if ($candidate.Folder -eq $kept.Folder) {
continue
}
$droppedVersion = if ($candidate.Version) { $candidate.Version.Raw } else { 'unknown' }
$null = & $Logger "Excluding stale duplicate driver package '$($candidate.Folder)' (DriverVer $droppedVersion) superseded by '$($kept.Folder)' (DriverVer $($kept.Version.Raw))."
}
}

return @($survivingFolders)
}

function Invoke-WinUtilISODism {
param (
[Parameter(Mandatory)][string[]]$Arguments,
Expand Down Expand Up @@ -192,26 +316,42 @@ function Invoke-WinUtilISOScript {
throw "Failed to stage $copyFailures boot-storage driver package folders."
}

& $Logger "Exported $($driverInfs.Count) driver INF files across $($driverFolders.Count) package folders; staged $storageCount boot-storage packages for WinPE."
$metadataBefore = Get-WinUtilISOWimMetadata -ImagePath $InstallImagePath -Index $InstallImageIndex
Assert-WinUtilISOWimMetadata -Before $metadataBefore
$stagedDriverFolders = @(Select-WinUtilISOStagedDriverPackages -DriverFolderGroups $driverFolders -Logger $Logger)
Comment thread
mewclouds marked this conversation as resolved.
if ($stagedDriverFolders.Count -eq 0) {
# Nothing safe to inject (e.g. every exported package was an Extension-class add-on)
# isn't a failure: leave install.wim untouched and continue building the ISO.
& $Logger 'No drivers found to inject: every exported package was excluded (Extension class or stale duplicate). Skipping driver injection; install.wim is unchanged.'
Comment thread
mewclouds marked this conversation as resolved.
Comment thread
mewclouds marked this conversation as resolved.
} else {
Comment thread
mewclouds marked this conversation as resolved.
$excludedFolders = @($driverFolders.Name | Where-Object { $_ -notin $stagedDriverFolders })
foreach ($excludedFolder in $excludedFolders) {
try {
Remove-Item -LiteralPath $excludedFolder -Recurse -Force -ErrorAction Stop
} catch {
throw "Failed to remove excluded driver package '$excludedFolder' before injection: $_"
}
}

& $Logger "Exported $($stagedDriverFolders.Count) of $($driverFolders.Count) driver packages ($storageCount staged for WinPE, $($excludedFolders.Count) excluded)."
$metadataBefore = Get-WinUtilISOWimMetadata -ImagePath $InstallImagePath -Index $InstallImageIndex
Assert-WinUtilISOWimMetadata -Before $metadataBefore

Set-ItemProperty -LiteralPath $InstallImagePath -Name IsReadOnly -Value $false
New-Item -Path $mountDir -ItemType Directory -Force | Out-Null
& $Logger "Mounting install.wim index $InstallImageIndex once for driver injection..."
Invoke-WinUtilISODism -Arguments @('/English', '/Mount-Image', "/ImageFile:$InstallImagePath", "/Index:$InstallImageIndex", "/MountDir:$mountDir") -Operation 'mount' | Out-Null
$imageMounted = $true
Set-ItemProperty -LiteralPath $InstallImagePath -Name IsReadOnly -Value $false
New-Item -Path $mountDir -ItemType Directory -Force | Out-Null
& $Logger "Mounting install.wim index $InstallImageIndex once for driver injection..."
Invoke-WinUtilISODism -Arguments @('/English', '/Mount-Image', "/ImageFile:$InstallImagePath", "/Index:$InstallImageIndex", "/MountDir:$mountDir") -Operation 'mount' | Out-Null
$imageMounted = $true

& $Logger "Adding all exported drivers to the selected Windows image in one DISM operation..."
Invoke-WinUtilISODism -Arguments @('/English', "/Image:$mountDir", '/Add-Driver', "/Driver:$driverExportRoot", '/Recurse') -Operation 'add-driver' | Out-Null
& $Logger "Adding all exported drivers to the selected Windows image in one DISM operation..."
Invoke-WinUtilISODism -Arguments @('/English', "/Image:$mountDir", '/Add-Driver', "/Driver:$driverExportRoot", '/Recurse') -Operation 'add-driver' | Out-Null

& $Logger 'Committing the driver-only install.wim change...'
Invoke-WinUtilISODism -Arguments @('/English', '/Unmount-Image', "/MountDir:$mountDir", '/Commit') -Operation 'commit' | Out-Null
$imageMounted = $false
& $Logger 'Committing the driver-only install.wim change...'
Invoke-WinUtilISODism -Arguments @('/English', '/Unmount-Image', "/MountDir:$mountDir", '/Commit') -Operation 'commit' | Out-Null
$imageMounted = $false

$metadataAfter = Get-WinUtilISOWimMetadata -ImagePath $InstallImagePath -Index $InstallImageIndex
Assert-WinUtilISOWimMetadata -Before $metadataBefore -After $metadataAfter
& $Logger 'Driver injection complete; install.wim metadata validation passed.'
$metadataAfter = Get-WinUtilISOWimMetadata -ImagePath $InstallImagePath -Index $InstallImageIndex
Assert-WinUtilISOWimMetadata -Before $metadataBefore -After $metadataAfter
& $Logger 'Driver injection complete; install.wim metadata validation passed.'
}
} finally {
if ($imageMounted -or (Test-WinUtilISOMountedImage -Path $mountDir)) {
try {
Expand Down
Loading