From db788c3c3045586a8be4d7b8fc5e69fe2bf6ff5d Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:13:29 -0800 Subject: [PATCH] =?UTF-8?q?-=20If=20not=20passing=20an=20ISO,=20hardcoded?= =?UTF-8?q?=20WindowsVersion=20of=2022H2=20for=20Windows=2010=20or=2024H2?= =?UTF-8?q?=20for=20Windows=2011=20since=20the=20ESD=20media=20only=20prov?= =?UTF-8?q?ides=20those=20two=20versions.=20Not=20doing=20this=20allowed?= =?UTF-8?q?=20for=20unnecessary=20VHDX=20creation=20since=20it=20checks=20?= =?UTF-8?q?the=20WindowsVersion=20via=20the=20json=20file.=20This=20also?= =?UTF-8?q?=20fixes=20an=20issue=20where=20CUs=20could=20be=20searched=20f?= =?UTF-8?q?or=20that=20didn=E2=80=99t=20exist,=20but=20the=20media=20would?= =?UTF-8?q?=20still=20download=20-=20Added=20some=20additional=20logging?= =?UTF-8?q?=20entries=20-=20Removed=20verbose=20output=20of=20the=20Optimi?= =?UTF-8?q?ze-Volume=20command=20-=20Fixed=20an=20issue=20where=20not=20pa?= =?UTF-8?q?ssing=20an=20ISO=20caused=20the=20script=20to=20fail=20-=20Clea?= =?UTF-8?q?ned=20up=20the=20KBPath=20folder=20at=20the=20end=20of=20the=20?= =?UTF-8?q?run=20-=20Changed=20some=20minor=20formatting=20items?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FFUDevelopment/BuildFFUVM.ps1 | 235 ++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 111 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index f0ced96..1148ae2 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -3900,6 +3900,17 @@ if (($WindowsArch -eq 'ARM64') -and ($UpdateLatestMSRT -eq $true)) { $UpdateLatestMSRT = $false WriteLog 'Windows Malicious Software Removal Tool is not available for the ARM64 architecture.' } +#If downloading ESD from MCT, hardcode WindowsVersion to 22H2 for Windows 10 and 24H2 for Windows 11 +#MCT media only provides 22H2 and 24H2 media +#This prevents issues with VHDX Caching unecessarily and with searching for CUs +if ($ISOPath -eq '') { + if ($WindowsRelease -eq '10') { + $WindowsVersion = '22H2' + } + if ($WindowsRelease -eq '11') { + $WindowsVersion = '24H2' + } +} ###END PARAMETER VALIDATION @@ -4208,7 +4219,7 @@ try { } #Update Latest Preview Cumlative Update for Client OS only - #will take Precendence over $UpdateLastestCU if both were set to $true + #will take Precendence over $UpdateLatestCU if both were set to $true if ($UpdatePreviewCU -and $installationType -eq 'Client') { Writelog "`$UpdatePreviewCU is set to true, checking for latest Preview CU" $Name = """Cumulative update Preview for Windows $WindowsRelease Version $WindowsVersion for $WindowsArch""" @@ -4262,37 +4273,41 @@ try { #Search for cached VHDX and skip VHDX creation if there's a cached version if ($AllowVHDXCaching) { + WriteLog 'AllowVHDXCaching is true, checking for cached VHDX file' if (Test-Path -Path $VHDXCacheFolder) { - $vhdxJsons = @(Get-ChildItem -File -Path $VHDXCacheFolder -Filter "*_config.json" | Sort-Object -Property CreationTime -Descending) + WriteLog "Found $VHDXCacheFolder" + $vhdxJsons = @(Get-ChildItem -File -Path $VHDXCacheFolder -Filter '*_config.json' | Sort-Object -Property CreationTime -Descending) + WriteLog "Found $($vhdxJsons.Count) cached VHDX files" $downloadedKBs = @(Get-ChildItem -File -Path $KBPath) #$jsonDeserializer = [System.Web.Script.Serialization.JavaScriptSerializer]::new() foreach ($vhdxJson in $vhdxJsons) { try { + WriteLog "Processing $($vhdxJson.FullName)" #$vhdxCacheItem = $jsonDeserializer.Deserialize((Get-Content -Path $vhdxJson.FullName -Raw), [VhdxCacheItem]) $vhdxCacheItem = Get-Content -Path $vhdxJson.FullName -Raw | ConvertFrom-Json if ((($vhdxCacheItem.WindowsSKU -ne $WindowsSKU) -or ([string]::IsNullOrEmpty($vhdxCacheItem.WindowsSKU) -xor [string]::IsNullOrEmpty($WindowsSKU)))) { - WriteLog "WindowsSKU not equal" + WriteLog 'WindowsSKU mismatch, continuing' continue } if ((($vhdxCacheItem.WindowsRelease -ne $WindowsRelease) -or ([string]::IsNullOrEmpty($vhdxCacheItem.WindowsRelease) -xor [string]::IsNullOrEmpty($WindowsRelease)))) { - WriteLog "WindowsRelease not equal" + WriteLog 'WindowsRelease mismatch, continuing' continue } if ((($vhdxCacheItem.WindowsVersion -ne $WindowsVersion) -or ([string]::IsNullOrEmpty($vhdxCacheItem.WindowsVersion) -xor [string]::IsNullOrEmpty($WindowsVersion)))) { - WriteLog "WindowsVersion not equal" + Writelog 'WindowsVersion mismatch, continuing' continue } if ((($vhdxCacheItem.OptionalFeatures -ne $OptionalFeatures) -or ([string]::IsNullOrEmpty($vhdxCacheItem.OptionalFeatures) -xor [string]::IsNullOrEmpty($OptionalFeatures)))) { - WriteLog "OptionalFeatures not equal" + WriteLog 'OptionalFeatures mismatch, continuing' continue } @@ -4300,11 +4315,11 @@ try { (Compare-Object -ReferenceObject $downloadedKBs -DifferenceObject $vhdxCacheItem.IncludedUpdates -Property Name) $downloadedKBs.Name $vhdxCacheItem.IncludedUpdates.Name - WriteLog "Updates not equal" + WriteLog 'IncludedUpdates mismatch, continuing' continue } - WriteLog "Found cached VHDX file with same parameters and patches" + WriteLog "Found cached VHDX file $vhdxCacheFolder\$($vhdxCacheItem.VhdxFileName) with matching parameters and included updates" $cachedVHDXFileFound = $true $cachedVHDXInfo = $vhdxCacheItem break @@ -4316,116 +4331,102 @@ try { } if (-Not $cachedVHDXFileFound) { - if ($ISOPath) { - $wimPath = Get-WimFromISO - } - else { - $wimPath = Get-WindowsESD -WindowsRelease $WindowsRelease -WindowsArch $WindowsArch -WindowsLang $WindowsLang -MediaType $mediaType - } - #If index not specified by user, try and find based on WindowsSKU - if (-not($index) -and ($WindowsSKU)) { - $index = Get-Index -WindowsImagePath $wimPath -WindowsSKU $WindowsSKU - } - - $vhdxDisk = New-ScratchVhdx -VhdxPath $VHDXPath -SizeBytes $disksize -LogicalSectorSizeBytes $LogicalSectorSizeBytes - - $systemPartitionDriveLetter = New-SystemPartition -VhdxDisk $vhdxDisk - - New-MSRPartition -VhdxDisk $vhdxDisk - - $osPartition = New-OSPartition -VhdxDisk $vhdxDisk -OSPartitionSize $OSPartitionSize -WimPath $WimPath -WimIndex $index - $osPartitionDriveLetter = $osPartition[1].DriveLetter - $WindowsPartition = $osPartitionDriveLetter + ":\" - - #$recoveryPartition = New-RecoveryPartition -VhdxDisk $vhdxDisk -OsPartition $osPartition[1] -RecoveryPartitionSize $RecoveryPartitionSize -DataPartition $dataPartition - $recoveryPartition = New-RecoveryPartition -VhdxDisk $vhdxDisk -OsPartition $osPartition[1] -RecoveryPartitionSize $RecoveryPartitionSize -DataPartition $dataPartition - - WriteLog "All necessary partitions created." - - Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1] - - if ($UpdateLatestCU -or $UpdateLatestNet -or $UpdatePreviewCU ) { - #Check if $KBCachePath exists, if not, create it - if ($AllowUpdateCaching) { - if (-not (Test-Path -Path $KBCachePath)) { - WriteLog "Creating $KBCachePath" - New-Item -Path $KBCachePath -ItemType Directory -Force | Out-Null - } + if ($ISOPath) { + $wimPath = Get-WimFromISO + } else { + $wimPath = Get-WindowsESD -WindowsRelease $WindowsRelease -WindowsArch $WindowsArch -WindowsLang $WindowsLang -MediaType $mediaType + } + #If index not specified by user, try and find based on WindowsSKU + if (-not($index) -and ($WindowsSKU)) { + $index = Get-Index -WindowsImagePath $wimPath -WindowsSKU $WindowsSKU } - } + $vhdxDisk = New-ScratchVhdx -VhdxPath $VHDXPath -SizeBytes $disksize -LogicalSectorSizeBytes $LogicalSectorSizeBytes + + $systemPartitionDriveLetter = New-SystemPartition -VhdxDisk $vhdxDisk + New-MSRPartition -VhdxDisk $vhdxDisk - #Add Windows packages - if ($UpdateLatestCU -or $UpdateLatestNet -or $UpdatePreviewCU ) { - try { - WriteLog "Adding KBs to $WindowsPartition" - WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient' - # If WindowsRelease is 2016, we need to add the SSU first - if ($WindowsRelease -eq 2016) { - WriteLog "WindowsRelease is 2016, adding SSU first" - WriteLog "Adding SSU to $WindowsPartition" - # Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath -PreventPending | Out-Null - # Commenting out -preventpending as it causes an issue with the SSU being applied - # Seems to be because of the registry being mounted per dism.log - Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath | Out-Null - WriteLog "SSU added to $WindowsPartition" - WriteLog "Removing $SSUFilePath" - Remove-Item -Path $SSUFilePath -Force | Out-Null - WriteLog 'SSU removed' - WriteLog "Adding CU to $WindowsPartition" - } - # Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath -PreventPending | Out-Null - Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath | Out-Null - WriteLog "KBs added to $WindowsPartition" - if ($AllowVHDXCaching) { - $cachedVHDXInfo = [VhdxCacheItem]::new() - $includedUpdates = Get-ChildItem -Path $KBPath -File - - foreach ($includedUpdate in $includedUpdates) { - $cachedVHDXInfo.IncludedUpdates += ([VhdxCacheUpdateItem]::new($includedUpdate.Name)) + $osPartition = New-OSPartition -VhdxDisk $vhdxDisk -OSPartitionSize $OSPartitionSize -WimPath $WimPath -WimIndex $index + $osPartitionDriveLetter = $osPartition[1].DriveLetter + $WindowsPartition = $osPartitionDriveLetter + ':\' + + #$recoveryPartition = New-RecoveryPartition -VhdxDisk $vhdxDisk -OsPartition $osPartition[1] -RecoveryPartitionSize $RecoveryPartitionSize -DataPartition $dataPartition + $recoveryPartition = New-RecoveryPartition -VhdxDisk $vhdxDisk -OsPartition $osPartition[1] -RecoveryPartitionSize $RecoveryPartitionSize -DataPartition $dataPartition + + WriteLog 'All necessary partitions created.' + + Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1] + + #Add Windows packages + if ($UpdateLatestCU -or $UpdateLatestNet -or $UpdatePreviewCU ) { + try { + WriteLog "Adding KBs to $WindowsPartition" + WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient' + # If WindowsRelease is 2016, we need to add the SSU first + if ($WindowsRelease -eq 2016) { + WriteLog 'WindowsRelease is 2016, adding SSU first' + WriteLog "Adding SSU to $WindowsPartition" + # Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath -PreventPending | Out-Null + # Commenting out -preventpending as it causes an issue with the SSU being applied + # Seems to be because of the registry being mounted per dism.log + Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath | Out-Null + WriteLog "SSU added to $WindowsPartition" + WriteLog "Removing $SSUFilePath" + Remove-Item -Path $SSUFilePath -Force | Out-Null + WriteLog 'SSU removed' + WriteLog "Adding CU to $WindowsPartition" } - } - WriteLog "Removing $KBPath" - Remove-Item -Path $KBPath -Recurse -Force | Out-Null - WriteLog "Clean Up the WinSxS Folder" - WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient' - Dism /Image:$WindowsPartition /Cleanup-Image /StartComponentCleanup /ResetBase | Out-Null - WriteLog "Clean Up the WinSxS Folder completed" + # Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath -PreventPending | Out-Null + Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath | Out-Null + WriteLog "KBs added to $WindowsPartition" + if ($AllowVHDXCaching) { + $cachedVHDXInfo = [VhdxCacheItem]::new() + $includedUpdates = Get-ChildItem -Path $KBPath -File + + foreach ($includedUpdate in $includedUpdates) { + $cachedVHDXInfo.IncludedUpdates += ([VhdxCacheUpdateItem]::new($includedUpdate.Name)) + } + } + WriteLog "Removing $KBPath" + Remove-Item -Path $KBPath -Recurse -Force | Out-Null + WriteLog 'Clean Up the WinSxS Folder' + WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient' + Dism /Image:$WindowsPartition /Cleanup-Image /StartComponentCleanup /ResetBase | Out-Null + WriteLog 'Clean Up the WinSxS Folder completed' + } catch { + Write-Host "Adding KB to VHDX failed with error $_" + WriteLog "Adding KB to VHDX failed with error $_" + if ($_.Exception.HResult -eq -2146498525) { + Write-Host 'Missing latest Servicing Stack Update' + Write-Host 'Media likely older than 2023-09 for Windows Server 2022 (KB5030216), or 2021-08 for Windows Server 2019 (KB5005112)' + Write-Host 'Recommended to use the latest media' + WriteLog 'Missing latest Servicing Stack Update' + WriteLog 'Media likely older than 2023-09 for Windows Server 2022 (KB5030216), or 2021-08 for Windows Server 2019 (KB5005112)' + WriteLog 'Recommended to use the latest media' + } + throw $_ + } } - catch { - Write-Host "Adding KB to VHDX failed with error $_" - WriteLog "Adding KB to VHDX failed with error $_" - if ($_.Exception.HResult -eq -2146498525){ - Write-Host 'Missing latest Servicing Stack Update' - Write-Host 'Media likely older than 2023-09 for Windows Server 2022 (KB5030216), or 2021-08 for Windows Server 2019 (KB5005112)' - Write-Host 'Recommended to use the latest media' - WriteLog 'Missing latest Servicing Stack Update' - WriteLog 'Media likely older than 2023-09 for Windows Server 2022 (KB5030216), or 2021-08 for Windows Server 2019 (KB5005112)' - WriteLog 'Recommended to use the latest media' - } - throw $_ - } - } - #Enable Windows Optional Features (e.g. .Net3, etc) - If ($OptionalFeatures) { - $Source = Join-Path (Split-Path $wimpath) "sxs" - Enable-WindowsFeaturesByName -FeatureNames $OptionalFeatures -Source $Source - } + #Enable Windows Optional Features (e.g. .Net3, etc) + If ($OptionalFeatures) { + $Source = Join-Path (Split-Path $wimpath) 'sxs' + Enable-WindowsFeaturesByName -FeatureNames $OptionalFeatures -Source $Source + } } else { #Use cached vhdx file - WriteLog "Using cached VHDX file to speed up build proces" + WriteLog 'Using cached VHDX file to speed up build proces' WriteLog "VHDX file is: $($cachedVHDXInfo.VhdxFileName)" Robocopy.exe $($VHDXCacheFolder) $($VMPath) $($cachedVHDXInfo.VhdxFileName) /E /COPY:DAT /R:5 /W:5 /J $VHDXPath = Join-Path $($VMPath) $($cachedVHDXInfo.VhdxFileName) $vhdxDisk = Get-VHD -Path $VHDXPath | Mount-VHD -Passthru | Get-Disk - $osPartition = $vhdxDisk | Get-Partition | Where-Object { $_.GptType -eq "{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}" } + $osPartition = $vhdxDisk | Get-Partition | Where-Object { $_.GptType -eq '{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}' } $osPartitionDriveLetter = $osPartition.DriveLetter - $WindowsPartition = $osPartitionDriveLetter + ":\" + $WindowsPartition = $osPartitionDriveLetter + ':\' } @@ -4439,9 +4440,11 @@ try { Dismount-DiskImage -ImagePath $ISOPath | Out-null WriteLog 'Done' } - else { - #Remove ESD file + #If $wimPath is an esd file, remove it + If ($wimPath -match '.esd') { + WriteLog "Deleting $wimPath file" Remove-Item -Path $wimPath -Force + WriteLog "$wimPath deleted" } @@ -4459,12 +4462,12 @@ try { } if ($AllowVHDXCaching -and !$cachedVHDXFileFound) { - WriteLog 'New cachabe VHDX created' + WriteLog 'New cached VHDX created' WriteLog 'Defragmenting Windows partition...' - Optimize-Volume -DriveLetter $osPartition.DriveLetter -Defrag -NormalPriority -Verbose + Optimize-Volume -DriveLetter $osPartition.DriveLetter -Defrag -NormalPriority WriteLog 'Performing slab consolidation on Windows partition...' - Optimize-Volume -DriveLetter $osPartition.DriveLetter -SlabConsolidate -NormalPriority -Verbose + Optimize-Volume -DriveLetter $osPartition.DriveLetter -SlabConsolidate -NormalPriority WriteLog 'Dismounting VHDX' Dismount-ScratchVhdx -VhdxPath $VHDXPath @@ -4737,20 +4740,30 @@ If ($CleanupAppsISO) { Writelog "Removing $AppsISO failed with error $_" throw $_ } -If ($CleanupDrivers){ +} +If ($CleanupDrivers) { try { If (Test-Path -Path $Driversfolder\$Make) { WriteLog "Removing $Driversfolder\$Make" Remove-Item -Path $Driversfolder\$Make -Force -Recurse - WriteLog "Removal complete" + WriteLog 'Removal complete' } - } - catch { + } catch { Writelog "Removing $Driversfolder\$Make failed with error $_" throw $_ } - } +if ($AllowVHDXCaching) { + try { + If (Test-Path -Path $KBPath) { + WriteLog "Removing $KBPath" + Remove-Item -Path $KBPath -Recurse -Force -ErrorAction SilentlyContinue + WriteLog 'Removal complete' + } + } catch { + Writelog "Removing $KBPath failed with error $_" + throw $_ + } } #Clean up dirty.txt file Remove-Item -Path .\dirty.txt -Force | out-null