Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
29 changes: 28 additions & 1 deletion catalogscrape/CatalogScrape.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,21 @@ function Invoke-DriverScrape {
foreach ($Target in $Config.Targets) {
Write-Host "`n=> Investigating Microsoft Update Catalog for $($Target.Name)..." -ForegroundColor Cyan
$AvailablePackages = @()
# Devices whose only candidates fell below their MinVersion floor — tracked so the
# manifest can say WHY they were skipped (vs the catalog returning nothing at all).
$floorBlocked = @{}

foreach ($Device in $Target.Devices) {
$deviceKey = $Device.Key
$label = $Device.Label
$titleExclude = if ($Device.ContainsKey('TitleExclude')) { @($Device.TitleExclude) } else { @() }
# Optional per-device version floor. Drivers below it are dropped — used when the
# only catalog matches for an HWID are a stale generic legacy driver (e.g. a 2016
# driver whose INF blankets dozens of PIDs), so the device skips rather than ships
# the antique. A real per-chip driver (whose [version] major encodes the model, e.g.
# 1157.x) clears the floor automatically once Realtek publishes it.
$minVersion = if ($Device.ContainsKey('MinVersion')) { ConvertTo-CsVersion $Device.MinVersion } else { $null }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If MinVersion is defined in the configuration but fails to parse (due to a typo or invalid format), it will silently return $null and skip the floor check. Adding a warning when MinVersion is present but cannot be parsed helps prevent silent failures and configuration errors.

            $minVersion = $null
            if ($Device.ContainsKey('MinVersion')) {
                $minVersion = ConvertTo-CsVersion $Device.MinVersion
                if (-not $minVersion) {
                    Write-Warning "Device $label has an unparseable MinVersion '$($Device.MinVersion)'."
                }
            }

$floorDropped = 0
$seenIds = [System.Collections.Generic.HashSet[string]]::new()

# Expand each base query into its dual-query-union variants, then dedup.
Expand Down Expand Up @@ -321,6 +331,12 @@ function Invoke-DriverScrape {
continue
}

if ($minVersion -and $ver -lt $minVersion) {
$floorDropped++
Write-Verbose "Dropped $label candidate $($d.Id): version $($d.Version) below MinVersion $($Device.MinVersion)."
continue
}

$AvailablePackages += [pscustomobject]@{
Key = $deviceKey
Label = $label
Expand All @@ -334,6 +350,12 @@ function Invoke-DriverScrape {
}
}
}

# A device whose every candidate was floored out: record why, for the manifest.
if ($minVersion -and $floorDropped -gt 0 -and -not ($AvailablePackages | Where-Object { $_.Key -eq $deviceKey })) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a pipeline with Where-Object inside a loop to check for the existence of a key in $AvailablePackages is inefficient and less idiomatic in PowerShell. Since $AvailablePackages is an array of custom objects, you can leverage member enumeration ($AvailablePackages.Key) and the -notin operator for a cleaner, faster, and more direct check.

            if ($minVersion -and $floorDropped -gt 0 -and $deviceKey -notin $AvailablePackages.Key) {

$floorBlocked[$deviceKey] = $Device.MinVersion
Write-Host " [!] ${label}: $floorDropped candidate(s) found but all below MinVersion $($Device.MinVersion); none selected." -ForegroundColor Yellow
}
}

if (-not $AvailablePackages) {
Expand All @@ -346,7 +368,12 @@ function Invoke-DriverScrape {
$foundKeys = @($AvailablePackages.Key | Select-Object -Unique)
foreach ($Device in $Target.Devices) {
if ($Device.Key -notin $foundKeys) {
$Manifest.Add("SKIPPED: $($Device.Label) (no catalog candidates)")
$reason = if ($floorBlocked.ContainsKey($Device.Key)) {
"all candidates below MinVersion $($floorBlocked[$Device.Key])"
} else {
'no catalog candidates'
}
$Manifest.Add("SKIPPED: $($Device.Label) ($reason)")
}
}

Expand Down
17 changes: 15 additions & 2 deletions catalogscrape/Test-CatalogScrape.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,16 @@ Assert { (Get-CsBranchRank ([version]'9.9.9.9') @('26.30')) -eq ([int]::MaxValue
$bestMt = Select-CsBestPackage -Packages @((Pkg '5.7.0.5659' '2026-03-06'), (Pkg '26.30.3.62' '2026-04-08')) -PreferredBranches @('26.30', '25.30', '5.7')
Assert { $bestMt.Version -eq [version]'26.30.3.62' } "MediaTek picks 26.30.3.62 (got $($bestMt.Version))"

# Realtek RTL8159: higher version wins DESPITE older catalog date (the core date-vs-version fix)
# Higher version wins DESPITE older catalog date (the core date-vs-version fix). NB: these two
# stale builds are exactly what RTL8157/8159 now floor out via MinVersion (asserted below).
$bestRtl = Select-CsBestPackage -Packages @((Pkg '11.19.602.2025' '2016-03-30'), (Pkg '11.19.20.602' '2018-03-30'))
Assert { $bestRtl.Version -eq [version]'11.19.602.2025' } "Realtek picks 11.19.602.2025 over newer-dated 11.19.20.602 (got $($bestRtl.Version))"
Assert { $bestRtl.Version -eq [version]'11.19.602.2025' } "version beats older date: picks 11.19.602.2025 over newer-dated 11.19.20.602 (got $($bestRtl.Version))"

# MinVersion floor (RTL8157/8159): the stale 2016/2018 generic driver is below the 1157/1159
# floor, so the device skips it; a real per-chip 115x.x driver clears the floor automatically.
Assert { ([version]'11.19.602.2025') -lt (ConvertTo-CsVersion '1157') } 'MinVersion floor: legacy 11.19.x is below the 1157 floor (8157/8159 skip the stale generic)'
Assert { (ConvertTo-CsVersion '1157.22.113.2026') -ge (ConvertTo-CsVersion '1157') } 'MinVersion floor: a real 1157.x driver clears the floor'
Assert { (ConvertTo-CsVersion '1159') -gt [version]'11.19.20.602' } 'MinVersion floor: 1159 floor sits above the legacy 815A driver'

# Intel I226-V: re-released older version has a NEWER date; highest version must still win
$bestIntel = Select-CsBestPackage -Packages @((Pkg '2.1.5.10' '2025-12-29'), (Pkg '2.1.5.7' '2026-01-19'))
Expand Down Expand Up @@ -150,6 +157,12 @@ Assert { $be.Queries[0] -eq 'VEN_8086&DEV_272B' } 'BE200 keeps correct 272B (not
$md = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'mediatek.psd1')
$mt7925 = $md.Targets.Devices | Where-Object Key -eq '7925'
Assert { $mt7925.PreferredBranches[0] -eq '26.30' } 'MT7925 preferred branch refreshed to 26.30'
# Realtek RTL8157/8159 carry a MinVersion floor so the stale 2016 generic driver is skipped.
$rt = Import-PowerShellDataFile (Join-Path $PSScriptRoot 'realtek.psd1')
$rt57 = $rt.Targets.Devices | Where-Object Key -eq '1157'
$rt59 = $rt.Targets.Devices | Where-Object Key -eq '1159'
Assert { (ConvertTo-CsVersion $rt57.MinVersion) -eq (ConvertTo-CsVersion '1157') } 'realtek RTL8157 has MinVersion 1157 floor'
Assert { (ConvertTo-CsVersion $rt59.MinVersion) -eq (ConvertTo-CsVersion '1159') } 'realtek RTL8159 has MinVersion 1159 floor'

"`n== RESULT: $script:pass passed, $script:fail failed =="
if ($script:fail -gt 0) { exit 1 } else { exit 0 }
15 changes: 9 additions & 6 deletions catalogscrape/realtek.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@
@{
Name = 'RTL_USB_Family'
Devices = @(
# USB packages carry a stale 2016/2018 catalog versionDate, so selection-by-date
# used to pick the OLDER build. The engine now selects by highest [version]
# (date as tiebreak), so e.g. RTL8159 correctly picks 11.19.602.2025 over the
# 2018-dated 11.19.20.602.
# Realtek publishes a per-PID modern USB NIC driver whose [version] major encodes
# the chip (8153->1153.x, 8156->1156.x, ...). RTL8153/8156 have current drivers
# (e.g. 1153.22.113.2026, Jan 2026).
@{ Key = '1153'; Label = 'RTL8153'; Queries = @('VID_0BDA&PID_8153') }
@{ Key = '1156'; Label = 'RTL8156'; Queries = @('VID_0BDA&PID_8156') }
@{ Key = '1157'; Label = 'RTL8157'; Queries = @('VID_0BDA&PID_8157') }
@{ Key = '1159'; Label = 'RTL8159'; Queries = @('VID_0BDA&PID_815A') }
# RTL8157 (5G) / RTL8159 (PID 815A) have NO modern catalog driver yet — the only
# match is a 2016/2018 generic legacy driver (11.19.602.2025) whose INF blankets
# ~16 old PIDs. MinVersion floors that out (11.x < 1157/1159), so these SKIP today
# and auto-pick the real per-chip driver the moment Realtek ships a 115x.x build.
@{ Key = '1157'; Label = 'RTL8157'; MinVersion = '1157'; Queries = @('VID_0BDA&PID_8157') }
@{ Key = '1159'; Label = 'RTL8159'; MinVersion = '1159'; Queries = @('VID_0BDA&PID_815A') }
)
}
)
Expand Down
Loading