Refactor update file discovery and cache comparison

Improves the reliability of finding update files (CU, CUP, .NET) by first using the exact filename from the update metadata. The script now only falls back to searching by KB article ID if the primary method fails.

Additionally, this enhances the VHDX cache lookup logic. The comparison now uses update file names extracted directly from their URLs, ensuring a more accurate match against the cached configuration.
This commit is contained in:
rbalsleyMSFT
2025-07-15 20:04:12 -07:00
parent 97e0998e1d
commit 7600ae86d1
+40 -31
View File
@@ -4651,7 +4651,13 @@ try {
$vhdxJsons = @(Get-ChildItem -File -Path $VHDXCacheFolder -Filter '*_config.json' | Sort-Object -Property CreationTime -Descending) $vhdxJsons = @(Get-ChildItem -File -Path $VHDXCacheFolder -Filter '*_config.json' | Sort-Object -Property CreationTime -Descending)
WriteLog "Found $($vhdxJsons.Count) cached VHDX config files" WriteLog "Found $($vhdxJsons.Count) cached VHDX config files"
$requiredUpdateNames = $requiredUpdates.Name | Sort-Object # Extract file names from URLs for comparison
$requiredUpdateFileNames = @()
foreach ($update in $requiredUpdates) {
$fileName = ($update.Url -split '/')[-1]
$requiredUpdateFileNames += $fileName
}
$requiredUpdateFileNames = $requiredUpdateFileNames | Sort-Object
foreach ($vhdxJson in $vhdxJsons) { foreach ($vhdxJson in $vhdxJsons) {
try { try {
@@ -4669,7 +4675,7 @@ try {
$cachedUpdateNames = $vhdxCacheItem.IncludedUpdates.Name | Sort-Object $cachedUpdateNames = $vhdxCacheItem.IncludedUpdates.Name | Sort-Object
} }
if ((Compare-Object -ReferenceObject $requiredUpdateNames -DifferenceObject $cachedUpdateNames).Length -gt 0) { if ((Compare-Object -ReferenceObject $requiredUpdateFileNames -DifferenceObject $cachedUpdateNames).Length -gt 0) {
WriteLog 'IncludedUpdates mismatch, continuing' WriteLog 'IncludedUpdates mismatch, continuing'
continue continue
} }
@@ -4722,30 +4728,30 @@ try {
WriteLog "Latest SSU identified as $SSUFilePath" WriteLog "Latest SSU identified as $SSUFilePath"
} }
if ($cuUpdateInfos.Count -gt 0) { if ($cuUpdateInfos.Count -gt 0) {
$CUFileName = (Get-ChildItem -Path $KBPath -Filter "*$cuKbArticleId*" -Recurse | Select-Object -First 1).Name # Use the actual downloaded file name from the update info
if (-not $CUFileName) { $CUFileName = $cuUpdateInfos[0].Name
WriteLog "Could not find CU file containing '$cuKbArticleId'. This can happen with Checkpoint CUs. Will try to find the most likely candidate from the update info list." $CUPath = (Get-ChildItem -Path $KBPath -Filter $CUFileName -Recurse).FullName
$CUFileName = ($cuUpdateInfos | Where-Object { $_.Name -match $cuKbArticleId } | Select-Object -First 1).Name if (-not $CUPath) {
if (-not $CUFileName) { # If exact match fails, try to find by KB article ID
WriteLog "Could not determine correct CU file from update info list. Using first in list as fallback." $CUPath = (Get-ChildItem -Path $KBPath -Filter "*$cuKbArticleId*" -Recurse | Select-Object -First 1).FullName
$CUFileName = $cuUpdateInfos[0].Name if ($CUPath) {
$CUFileName = Split-Path $CUPath -Leaf
} }
} }
$CUPath = (Get-ChildItem -Path $KBPath -Filter $CUFileName -Recurse).FullName
WriteLog "Latest CU identified as $CUPath" WriteLog "Latest CU identified as $CUPath"
} }
if ($cupUpdateInfos.Count -gt 0) { if ($cupUpdateInfos.Count -gt 0) {
$CUPFileName = (Get-ChildItem -Path $KBPath -Filter "*$cupKbArticleId*" -Recurse | Select-Object -First 1).Name # Use the actual downloaded file name from the update info
if (-not $CUPFileName) { $CUPFileName = $cupUpdateInfos[0].Name
WriteLog "Could not find CU file containing '$cupKbArticleId'. This can happen with Checkpoint CUs. Will try to find the most likely candidate from the update info list." $CUPPath = (Get-ChildItem -Path $KBPath -Filter $CUPFileName -Recurse).FullName
$CUPFileName = ($cupUpdateInfos | Where-Object { $_.Name -match $cupKbArticleId } | Select-Object -First 1).Name if (-not $CUPPath) {
if (-not $CUPFileName) { # If exact match fails, try to find by KB article ID
WriteLog "Could not determine correct CU file from update info list. Using first in list as fallback." $CUPPath = (Get-ChildItem -Path $KBPath -Filter "*$cupKbArticleId*" -Recurse | Select-Object -First 1).FullName
$CUPFileName = $cupUpdateInfos[0].Name if ($CUPPath) {
$CUPFileName = Split-Path $CUPPath -Leaf
} }
} }
$CUPPath = (Get-ChildItem -Path $KBPath -Filter $CUPFileName -Recurse).FullName WriteLog "Latest Preview CU identified as $CUPPath"
WriteLog "Latest CU identified as $CUPPath"
} }
if ($netUpdateInfos.Count -gt 0 -or $netFeatureUpdateInfos.Count -gt 0) { if ($netUpdateInfos.Count -gt 0 -or $netFeatureUpdateInfos.Count -gt 0) {
if ($isLTSC -and $WindowsRelease -in 2016, 2019, 2021) { if ($isLTSC -and $WindowsRelease -in 2016, 2019, 2021) {
@@ -4753,13 +4759,16 @@ try {
WriteLog ".NET updates for LTSC are in $NETPath" WriteLog ".NET updates for LTSC are in $NETPath"
} }
else { else {
$NETFileName = (Get-ChildItem -Path $KBPath -Filter "*$netKbArticleId*" -Recurse | Select-Object -First 1).Name # Use the actual downloaded file name from the update info
if (-not $NETFileName) { $NETFileName = $netUpdateInfos[0].Name
WriteLog "Could not find .NET file containing '$netKbArticleId'. Using first in list as fallback."
$NETFileName = ($netUpdateInfos | Where-Object { $_.Name -match $netKbArticleId } | Select-Object -First 1).Name
if (-not $NETFileName) { $NETFileName = $netUpdateInfos[0].Name }
}
$NETPath = (Get-ChildItem -Path $KBPath -Filter $NETFileName -Recurse).FullName $NETPath = (Get-ChildItem -Path $KBPath -Filter $NETFileName -Recurse).FullName
if (-not $NETPath) {
# If exact match fails, try to find by KB article ID
$NETPath = (Get-ChildItem -Path $KBPath -Filter "*$netKbArticleId*" -Recurse | Select-Object -First 1).FullName
if ($NETPath) {
$NETFileName = Split-Path $NETPath -Leaf
}
}
WriteLog "Latest .NET Framework identified as $NETPath" WriteLog "Latest .NET Framework identified as $NETPath"
} }
} }
@@ -4815,18 +4824,18 @@ try {
# Seems to be because of the registry being mounted per dism.log # Seems to be because of the registry being mounted per dism.log
Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath | Out-Null Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath | Out-Null
WriteLog "SSU added to $WindowsPartition" WriteLog "SSU added to $WindowsPartition"
WriteLog "Removing $SSUFilePath" # WriteLog "Removing $SSUFilePath"
Remove-Item -Path $SSUFilePath -Force | Out-Null # Remove-Item -Path $SSUFilePath -Force | Out-Null
WriteLog 'SSU removed' # WriteLog 'SSU removed'
} }
if ($WindowsRelease -in 2016, 2019, 2021 -and $isLTSC) { if ($WindowsRelease -in 2016, 2019, 2021 -and $isLTSC) {
WriteLog "WindowsRelease is $WindowsRelease and is $WindowsSKU, adding SSU first" WriteLog "WindowsRelease is $WindowsRelease and is $WindowsSKU, adding SSU first"
WriteLog "Adding SSU to $WindowsPartition" WriteLog "Adding SSU to $WindowsPartition"
Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath | Out-Null Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath | Out-Null
WriteLog "SSU added to $WindowsPartition" WriteLog "SSU added to $WindowsPartition"
WriteLog "Removing $SSUFilePath" # WriteLog "Removing $SSUFilePath"
Remove-Item -Path $SSUFilePath -Force | Out-Null # Remove-Item -Path $SSUFilePath -Force | Out-Null
WriteLog 'SSU removed' # WriteLog 'SSU removed'
} }
# Break out CU and NET updates to be added separately to abide by Checkpoint Update recommendations # Break out CU and NET updates to be added separately to abide by Checkpoint Update recommendations
if ($UpdateLatestCU) { if ($UpdateLatestCU) {