- If not passing an ISO, hardcoded WindowsVersion of 22H2 for Windows 10 or 24H2 for Windows 11 since the ESD media only provides those two versions. Not doing this allowed for unnecessary VHDX creation since it checks the WindowsVersion via the json file. This also fixes an issue where CUs could be searched for that didn’t exist, but the media would still download

- Added some additional logging entries
- Removed verbose output of the Optimize-Volume command
- Fixed an issue where not passing an ISO caused the script to fail
- Cleaned up the KBPath folder at the end of the run
- Changed some minor formatting items
This commit is contained in:
rbalsleyMSFT
2024-11-27 13:13:29 -08:00
parent 0f3380e91e
commit db788c3c30
+124 -111
View File
@@ -3900,6 +3900,17 @@ if (($WindowsArch -eq 'ARM64') -and ($UpdateLatestMSRT -eq $true)) {
$UpdateLatestMSRT = $false $UpdateLatestMSRT = $false
WriteLog 'Windows Malicious Software Removal Tool is not available for the ARM64 architecture.' 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 ###END PARAMETER VALIDATION
@@ -4208,7 +4219,7 @@ try {
} }
#Update Latest Preview Cumlative Update for Client OS only #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') { if ($UpdatePreviewCU -and $installationType -eq 'Client') {
Writelog "`$UpdatePreviewCU is set to true, checking for latest Preview CU" Writelog "`$UpdatePreviewCU is set to true, checking for latest Preview CU"
$Name = """Cumulative update Preview for Windows $WindowsRelease Version $WindowsVersion for $WindowsArch""" $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 #Search for cached VHDX and skip VHDX creation if there's a cached version
if ($AllowVHDXCaching) { if ($AllowVHDXCaching) {
WriteLog 'AllowVHDXCaching is true, checking for cached VHDX file'
if (Test-Path -Path $VHDXCacheFolder) { 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) $downloadedKBs = @(Get-ChildItem -File -Path $KBPath)
#$jsonDeserializer = [System.Web.Script.Serialization.JavaScriptSerializer]::new() #$jsonDeserializer = [System.Web.Script.Serialization.JavaScriptSerializer]::new()
foreach ($vhdxJson in $vhdxJsons) { foreach ($vhdxJson in $vhdxJsons) {
try { try {
WriteLog "Processing $($vhdxJson.FullName)"
#$vhdxCacheItem = $jsonDeserializer.Deserialize((Get-Content -Path $vhdxJson.FullName -Raw), [VhdxCacheItem]) #$vhdxCacheItem = $jsonDeserializer.Deserialize((Get-Content -Path $vhdxJson.FullName -Raw), [VhdxCacheItem])
$vhdxCacheItem = Get-Content -Path $vhdxJson.FullName -Raw | ConvertFrom-Json $vhdxCacheItem = Get-Content -Path $vhdxJson.FullName -Raw | ConvertFrom-Json
if ((($vhdxCacheItem.WindowsSKU -ne $WindowsSKU) -or if ((($vhdxCacheItem.WindowsSKU -ne $WindowsSKU) -or
([string]::IsNullOrEmpty($vhdxCacheItem.WindowsSKU) -xor [string]::IsNullOrEmpty($WindowsSKU)))) { ([string]::IsNullOrEmpty($vhdxCacheItem.WindowsSKU) -xor [string]::IsNullOrEmpty($WindowsSKU)))) {
WriteLog "WindowsSKU not equal" WriteLog 'WindowsSKU mismatch, continuing'
continue continue
} }
if ((($vhdxCacheItem.WindowsRelease -ne $WindowsRelease) -or if ((($vhdxCacheItem.WindowsRelease -ne $WindowsRelease) -or
([string]::IsNullOrEmpty($vhdxCacheItem.WindowsRelease) -xor [string]::IsNullOrEmpty($WindowsRelease)))) { ([string]::IsNullOrEmpty($vhdxCacheItem.WindowsRelease) -xor [string]::IsNullOrEmpty($WindowsRelease)))) {
WriteLog "WindowsRelease not equal" WriteLog 'WindowsRelease mismatch, continuing'
continue continue
} }
if ((($vhdxCacheItem.WindowsVersion -ne $WindowsVersion) -or if ((($vhdxCacheItem.WindowsVersion -ne $WindowsVersion) -or
([string]::IsNullOrEmpty($vhdxCacheItem.WindowsVersion) -xor [string]::IsNullOrEmpty($WindowsVersion)))) { ([string]::IsNullOrEmpty($vhdxCacheItem.WindowsVersion) -xor [string]::IsNullOrEmpty($WindowsVersion)))) {
WriteLog "WindowsVersion not equal" Writelog 'WindowsVersion mismatch, continuing'
continue continue
} }
if ((($vhdxCacheItem.OptionalFeatures -ne $OptionalFeatures) -or if ((($vhdxCacheItem.OptionalFeatures -ne $OptionalFeatures) -or
([string]::IsNullOrEmpty($vhdxCacheItem.OptionalFeatures) -xor [string]::IsNullOrEmpty($OptionalFeatures)))) { ([string]::IsNullOrEmpty($vhdxCacheItem.OptionalFeatures) -xor [string]::IsNullOrEmpty($OptionalFeatures)))) {
WriteLog "OptionalFeatures not equal" WriteLog 'OptionalFeatures mismatch, continuing'
continue continue
} }
@@ -4300,11 +4315,11 @@ try {
(Compare-Object -ReferenceObject $downloadedKBs -DifferenceObject $vhdxCacheItem.IncludedUpdates -Property Name) (Compare-Object -ReferenceObject $downloadedKBs -DifferenceObject $vhdxCacheItem.IncludedUpdates -Property Name)
$downloadedKBs.Name $downloadedKBs.Name
$vhdxCacheItem.IncludedUpdates.Name $vhdxCacheItem.IncludedUpdates.Name
WriteLog "Updates not equal" WriteLog 'IncludedUpdates mismatch, continuing'
continue 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 $cachedVHDXFileFound = $true
$cachedVHDXInfo = $vhdxCacheItem $cachedVHDXInfo = $vhdxCacheItem
break break
@@ -4316,116 +4331,102 @@ try {
} }
if (-Not $cachedVHDXFileFound) { if (-Not $cachedVHDXFileFound) {
if ($ISOPath) { if ($ISOPath) {
$wimPath = Get-WimFromISO $wimPath = Get-WimFromISO
} } else {
else { $wimPath = Get-WindowsESD -WindowsRelease $WindowsRelease -WindowsArch $WindowsArch -WindowsLang $WindowsLang -MediaType $mediaType
$wimPath = Get-WindowsESD -WindowsRelease $WindowsRelease -WindowsArch $WindowsArch -WindowsLang $WindowsLang -MediaType $mediaType }
} #If index not specified by user, try and find based on WindowsSKU
#If index not specified by user, try and find based on WindowsSKU if (-not($index) -and ($WindowsSKU)) {
if (-not($index) -and ($WindowsSKU)) { $index = Get-Index -WindowsImagePath $wimPath -WindowsSKU $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
}
} }
}
$vhdxDisk = New-ScratchVhdx -VhdxPath $VHDXPath -SizeBytes $disksize -LogicalSectorSizeBytes $LogicalSectorSizeBytes
$systemPartitionDriveLetter = New-SystemPartition -VhdxDisk $vhdxDisk
#Add Windows packages New-MSRPartition -VhdxDisk $vhdxDisk
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) { $osPartition = New-OSPartition -VhdxDisk $vhdxDisk -OSPartitionSize $OSPartitionSize -WimPath $WimPath -WimIndex $index
$cachedVHDXInfo.IncludedUpdates += ([VhdxCacheUpdateItem]::new($includedUpdate.Name)) $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"
} }
} # Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath -PreventPending | Out-Null
WriteLog "Removing $KBPath" Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath | Out-Null
Remove-Item -Path $KBPath -Recurse -Force | Out-Null WriteLog "KBs added to $WindowsPartition"
WriteLog "Clean Up the WinSxS Folder" if ($AllowVHDXCaching) {
WriteLog 'This can take 10+ minutes depending on how old the media is and the size of the KB. Please be patient' $cachedVHDXInfo = [VhdxCacheItem]::new()
Dism /Image:$WindowsPartition /Cleanup-Image /StartComponentCleanup /ResetBase | Out-Null $includedUpdates = Get-ChildItem -Path $KBPath -File
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 $_
}
}
#Enable Windows Optional Features (e.g. .Net3, etc) foreach ($includedUpdate in $includedUpdates) {
If ($OptionalFeatures) { $cachedVHDXInfo.IncludedUpdates += ([VhdxCacheUpdateItem]::new($includedUpdate.Name))
$Source = Join-Path (Split-Path $wimpath) "sxs" }
Enable-WindowsFeaturesByName -FeatureNames $OptionalFeatures -Source $Source }
} 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 $_
}
}
#Enable Windows Optional Features (e.g. .Net3, etc)
If ($OptionalFeatures) {
$Source = Join-Path (Split-Path $wimpath) 'sxs'
Enable-WindowsFeaturesByName -FeatureNames $OptionalFeatures -Source $Source
}
} else { } else {
#Use cached vhdx file #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)" WriteLog "VHDX file is: $($cachedVHDXInfo.VhdxFileName)"
Robocopy.exe $($VHDXCacheFolder) $($VMPath) $($cachedVHDXInfo.VhdxFileName) /E /COPY:DAT /R:5 /W:5 /J Robocopy.exe $($VHDXCacheFolder) $($VMPath) $($cachedVHDXInfo.VhdxFileName) /E /COPY:DAT /R:5 /W:5 /J
$VHDXPath = Join-Path $($VMPath) $($cachedVHDXInfo.VhdxFileName) $VHDXPath = Join-Path $($VMPath) $($cachedVHDXInfo.VhdxFileName)
$vhdxDisk = Get-VHD -Path $VHDXPath | Mount-VHD -Passthru | Get-Disk $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 $osPartitionDriveLetter = $osPartition.DriveLetter
$WindowsPartition = $osPartitionDriveLetter + ":\" $WindowsPartition = $osPartitionDriveLetter + ':\'
} }
@@ -4439,9 +4440,11 @@ try {
Dismount-DiskImage -ImagePath $ISOPath | Out-null Dismount-DiskImage -ImagePath $ISOPath | Out-null
WriteLog 'Done' WriteLog 'Done'
} }
else { #If $wimPath is an esd file, remove it
#Remove ESD file If ($wimPath -match '.esd') {
WriteLog "Deleting $wimPath file"
Remove-Item -Path $wimPath -Force Remove-Item -Path $wimPath -Force
WriteLog "$wimPath deleted"
} }
@@ -4459,12 +4462,12 @@ try {
} }
if ($AllowVHDXCaching -and !$cachedVHDXFileFound) { if ($AllowVHDXCaching -and !$cachedVHDXFileFound) {
WriteLog 'New cachabe VHDX created' WriteLog 'New cached VHDX created'
WriteLog 'Defragmenting Windows partition...' 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...' 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' WriteLog 'Dismounting VHDX'
Dismount-ScratchVhdx -VhdxPath $VHDXPath Dismount-ScratchVhdx -VhdxPath $VHDXPath
@@ -4737,20 +4740,30 @@ If ($CleanupAppsISO) {
Writelog "Removing $AppsISO failed with error $_" Writelog "Removing $AppsISO failed with error $_"
throw $_ throw $_
} }
If ($CleanupDrivers){ }
If ($CleanupDrivers) {
try { try {
If (Test-Path -Path $Driversfolder\$Make) { If (Test-Path -Path $Driversfolder\$Make) {
WriteLog "Removing $Driversfolder\$Make" WriteLog "Removing $Driversfolder\$Make"
Remove-Item -Path $Driversfolder\$Make -Force -Recurse Remove-Item -Path $Driversfolder\$Make -Force -Recurse
WriteLog "Removal complete" WriteLog 'Removal complete'
} }
} } catch {
catch {
Writelog "Removing $Driversfolder\$Make failed with error $_" Writelog "Removing $Driversfolder\$Make failed with error $_"
throw $_ 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 #Clean up dirty.txt file
Remove-Item -Path .\dirty.txt -Force | out-null Remove-Item -Path .\dirty.txt -Force | out-null