Add support for LTSC versions of Windows

This commit is contained in:
Zehadi Alam
2024-12-28 20:01:01 -05:00
parent ce7af09f25
commit bc4a181182
2 changed files with 104 additions and 15 deletions
+101 -14
View File
@@ -224,7 +224,7 @@ param(
[Parameter(Mandatory = $false, Position = 0)]
[ValidateScript({ Test-Path $_ })]
[string]$ISOPath,
[ValidateSet('Home', 'Home N', 'Home Single Language', 'Education', 'Education N', 'Pro', 'Pro N', 'Pro Education', 'Pro Education N', 'Pro for Workstations', 'Pro N for Workstations', 'Enterprise', 'Enterprise N', 'Standard', 'Standard (Desktop Experience)', 'Datacenter', 'Datacenter (Desktop Experience)')]
[ValidateSet('Home', 'Home N', 'Home Single Language', 'Education', 'Education N', 'Pro', 'Pro N', 'Pro Education', 'Pro Education N', 'Pro for Workstations', 'Pro N for Workstations', 'Enterprise', 'Enterprise N', 'Enterprise LTSC', 'Enterprise N LTSC', 'IoT Enterprise LTSC', 'IoT Enterprise N LTSC', 'Standard', 'Standard (Desktop Experience)', 'Datacenter', 'Datacenter (Desktop Experience)')]
[string]$WindowsSKU = 'Pro',
[ValidateScript({ Test-Path $_ })]
[string]$FFUDevelopmentPath = $PSScriptRoot,
@@ -284,7 +284,7 @@ param(
[string]$ProductKey,
[bool]$BuildUSBDrive,
[Parameter(Mandatory = $false)]
[ValidateSet(10, 11, 2016, 2019, 2022, 2025)]
[ValidateSet(10, 11, 2016, 2019, 2021, 2022, 2024, 2025)]
[int]$WindowsRelease = 11,
[Parameter(Mandatory = $false)]
[string]$WindowsVersion = '24h2',
@@ -400,6 +400,26 @@ if ($ConfigFile -and (Test-Path -Path $ConfigFile)) {
}
}
$clientSKUs = @('Home', 'Home N', 'Home Single Language', 'Education', 'Education N', 'Pro', 'Pro N', 'Pro Education', 'Pro Education N', 'Pro for Workstations', 'Pro N for Workstations', 'Enterprise', 'Enterprise N')
$LTSCSKUs = @('Enterprise LTSC', 'Enterprise N LTSC', 'IoT Enterprise LTSC', 'IoT Enterprise N LTSC')
$ServerSKUs = @('Standard', 'Standard (Desktop Experience)', 'Datacenter', 'Datacenter (Desktop Experience)')
$releaseToSKUMapping = @{
10 = $clientSKUs
11 = $clientSKUs
2016 = $LTSCSKUs + $ServerSKUs
2019 = $LTSCSKUs + $ServerSKUs
2021 = $LTSCSKUs
2022 = $ServerSKUs
2024 = $LTSCSKUs
2025 = $ServerSKUs
}
if ($releaseToSKUMapping.ContainsKey($WindowsRelease) -and $WindowsSKU -notin $releaseToSKUMapping[$WindowsRelease]) {
throw "Selected SKU is $WindowsSKU. Windows $WindowsRelease requires one of these SKUs: $($releaseToSKUMapping[$WindowsRelease] -join ', ')"
}
if ($WindowsRelease -notin 10, 11 -and -not $ISOPath) {
throw "Windows $WindowsRelease cannot automatically be downloaded. Please specify your own ISO using the -ISOPath parameter."
}
#Class definition for vhdx cache
class VhdxCacheUpdateItem {
[string]$Name
@@ -461,7 +481,7 @@ if (-not $UnattendFolder) { $UnattendFolder = "$FFUDevelopmentPath\Unattend" }
if (-not $AutopilotFolder) { $AutopilotFolder = "$FFUDevelopmentPath\Autopilot" }
if (-not $PEDriversFolder) { $PEDriversFolder = "$FFUDevelopmentPath\PEDrivers" }
if (-not $VHDXCacheFolder) { $VHDXCacheFolder = "$FFUDevelopmentPath\VHDXCache" }
if (-not $installationType) { $installationType = if ($WindowsRelease.ToString().Length -eq 2) { 'Client' } else { 'Server' } }
if (-not $installationType) { $installationType = if ($WindowsSKU -like "Standard*" -or $WindowsSKU -like "Datacenter*") { 'Server' } else { 'Client' } }
if ($installationType -eq 'Server'){
#Map $WindowsRelease to $WindowsVersion for Windows Server
switch ($WindowsRelease) {
@@ -472,6 +492,15 @@ if ($installationType -eq 'Server'){
}
}
if ($WindowsSKU -like "*LTSC") {
switch ($WindowsRelease) {
2016 { $WindowsVersion = '1607' }
2019 { $WindowsVersion = '1809' }
2021 { $WindowsVersion = '21H2' }
2024 { $WindowsVersion = '24H2' }
}
}
#FUNCTIONS
function WriteLog($LogText) {
Add-Content -path $LogFile -value "$((Get-Date).ToString()) $LogText" -Force -ErrorAction SilentlyContinue
@@ -1809,7 +1838,7 @@ function Get-WindowsESD {
elseif ($WindowsRelease -eq 11) {
'https://go.microsoft.com/fwlink/?LinkId=2156292'
} else {
throw "Downloading Windows Server is not supported. Please use the -ISOPath parameter to specify the path to the Windows Server ISO file."
throw "Downloading Windows $WindowsRelease is not supported. Please use the -ISOPath parameter to specify the path to the Windows $WindowsRelease ISO file."
}
# Download cab file
@@ -2619,6 +2648,10 @@ function Get-WimIndex {
'Pro_Edu_N' { 9 }
'Pro_WKS' { 10 }
'Pro_WKS_N' { 11 }
'Enterprise' { 3 }
'Enterprise N' { 4 }
'Enterprise LTSC' { 1 }
'Enterprise N LTSC' { 2 }
Default { 6 }
}
}
@@ -3371,6 +3404,8 @@ Function Get-WindowsVersionInfo {
Professional { 'Pro' }
ProfessionalEducation { 'Pro_Edu' }
Enterprise { 'Ent' }
EnterpriseS { 'Ent_LTSC' }
IoTEnterpriseS { 'IoT_Ent_LTSC' }
Education { 'Edu' }
ProfessionalWorkstation { 'Pro_Wks' }
ServerStandard { 'Srv_Std' }
@@ -4356,9 +4391,15 @@ if ($InstallApps) {
if ($UpdateLatestMSRT) {
WriteLog "`$UpdateLatestMSRT is set to true."
if ($WindowsArch -eq 'x64') {
if ($installationType -eq 'client') {
if ($WindowsRelease -in 10, 11) {
$Name = """Windows Malicious Software Removal Tool x64""" + " " + """Windows $WindowsRelease"""
}
elseif ($WindowsRelease -in 2016, 2019, 2021 -and $WindowsSKU -like "*LTSC") {
$Name = """Windows Malicious Software Removal Tool x64""" + " " + """Windows 10"""
}
elseif ($WindowsRelease -in 2024 -and $WindowsSKU -like "*LTSC") {
$Name = """Windows Malicious Software Removal Tool x64""" + " " + """Windows 11"""
}
#Windows Server 2025 isn't listed as a product in the Microsoft Update Catalog, so we'll use the 2019 version
elseif ($installationType -eq 'server' -and $WindowsRelease -eq '24H2') {
$Name = """Windows Malicious Software Removal Tool x64""" + " " + """Windows Server 2019"""
@@ -4495,7 +4536,7 @@ try {
#The Windows release info page is updated later than the MU Catalog
if ($UpdateLatestCU -and -not $UpdatePreviewCU) {
Writelog "`$UpdateLatestCU is set to true, checking for latest CU"
if ($installationType -eq 'Client') {
if ($WindowsRelease -in 10, 11) {
$Name = """Cumulative update for Windows $WindowsRelease Version $WindowsVersion for $WindowsArch"""
}
if ($WindowsRelease -eq 2025) {
@@ -4504,9 +4545,20 @@ try {
if ($WindowsRelease -eq 2022) {
$Name = """Cumulative Update for Microsoft server operating system, version 21h2 for $WindowsArch"""
}
if ($WindowsRelease -in 2016, 2019) {
if ($WindowsRelease -in 2016, 2019 -and $installationType -eq "Server") {
$Name = """Cumulative update for Windows Server $WindowsRelease for $WindowsArch"""
}
if ($WindowsRelease -in 2016, 2019, 2021 -and $WindowsSKU -like "*LTSC") {
$today = Get-Date
$firstDayOfMonth = Get-Date -Year $today.Year -Month $today.Month -Day 1
$secondTuesday = $firstDayOfMonth.AddDays(((2 - [int]$firstDayOfMonth.DayOfWeek + 7) % 7) + 7)
$updateDate = if ($today -gt $secondTuesday) { $today } else { $today.AddMonths(-1) }
# More precise search to prevent Dynamic cumulative update from being chosen.
$Name = """$($updateDate.ToString('yyyy-MM')) Cumulative update for Windows 10 Version $WindowsVersion for $WindowsArch"""
}
if ($WindowsRelease -eq 2024 -and $WindowsSKU -like "*LTSC") {
$Name = """Cumulative update for Windows 11 Version $WindowsVersion for $WindowsArch"""
}
#Check if $KBPath exists, if not, create it
If (-not (Test-Path -Path $KBPath)) {
WriteLog "Creating $KBPath"
@@ -4520,6 +4572,13 @@ try {
$SSUFilePath = "$KBPath\$SSUFile"
WriteLog "Latest SSU saved to $SSUFilePath"
}
if ($WindowsRelease -in 2016, 2019, 2021 -and $WindowsSKU -like "*LTSC") {
$SSUName = """Servicing Stack Update for Windows 10 Version $WindowsVersion for $WindowsArch"""
WriteLog "Searching for $SSUName from Microsoft Update Catalog and saving to $KBPath"
$SSUFile = Save-KB -Name $SSUName -Path $KBPath
$SSUFilePath = "$KBPath\$SSUFile"
WriteLog "Latest SSU saved to $SSUFilePath"
}
WriteLog "Searching for $name from Microsoft Update Catalog and saving to $KBPath"
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "Latest CU saved to $KBPath\$KBFilePath"
@@ -4527,7 +4586,7 @@ try {
#Update Latest Preview Cumlative Update for Client OS only
#will take Precendence over $UpdateLatestCU if both were set to $true
if ($UpdatePreviewCU -and $installationType -eq 'Client') {
if ($UpdatePreviewCU -and $installationType -eq 'Client' -and $WindowsSKU -notlike "*LTSC") {
Writelog "`$UpdatePreviewCU is set to true, checking for latest Preview CU"
$Name = """Cumulative update Preview for Windows $WindowsRelease Version $WindowsVersion for $WindowsArch"""
#Check if $KBPath exists, if not, create it
@@ -4543,8 +4602,8 @@ try {
#Update Latest .NET Framework
if ($UpdateLatestNet) {
Writelog "`$UpdateLatestNet is set to true, checking for latest .NET Framework"
if ($installationType -eq 'Client') {
$Name = "Cumulative update for .net framework windows $WindowsRelease $WindowsVersion $WindowsArch -preview"
if ($WindowsRelease -in 10, 11) {
$Name = "Cumulative update for .NET framework windows $WindowsRelease $WindowsVersion $WindowsArch -preview"
}
if ($WindowsRelease -eq 2025) {
$Name = """Cumulative Update for .NET Framework"" ""3.5 and 4.8.1"" for Windows 11 24H2 x64 -preview"
@@ -4552,12 +4611,18 @@ try {
if ($WindowsRelease -eq 2022) {
$Name = """Cumulative Update for .NET Framework 3.5, 4.8 and 4.8.1"" ""operating system version 21H2 for x64"""
}
if ($WindowsRelease -eq 2019) {
if ($WindowsRelease -eq 2019 -and $installationType -eq "Server") {
$Name = """Cumulative Update for .NET Framework 3.5, 4.7.2 and 4.8 for Windows Server 2019 for x64"""
}
if ($WindowsRelease -eq 2016) {
if ($WindowsRelease -eq 2016 -and $installationType -eq "Server") {
$Name = """Cumulative Update for .NET Framework 4.8 for Windows Server 2016 for x64"""
}
if ($WindowsRelease -in 2016, 2019, 2021 -and $WindowsSKU -like "*LTSC") {
$Name = "Cumulative update for .net framework windows 10 $WindowsVersion $WindowsArch"
}
if ($WindowsRelease -eq 2024) {
$Name = "Cumulative update for .NET framework windows 11 $WindowsVersion $WindowsArch"
}
#Check if $KBPath exists, if not, create it
If (-not (Test-Path -Path $KBPath)) {
WriteLog "Creating $KBPath"
@@ -4566,6 +4631,18 @@ try {
WriteLog "Searching for $name from Microsoft Update Catalog and saving to $KBPath"
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "Latest .NET saved to $KBPath\$KBFilePath"
if ($WindowsRelease -eq 2021) {
WriteLog "Checking for latest .NET Framework feature pack for Windows $WindowsRelease $WindowsSKU"
$Name = """Microsoft .NET Framework 4.8.1 for Windows 10 Version 21H2 for x64"""
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "Latest .NET Framework feature pack saved to $KBPath\$KBFilePath"
}
if ($WindowsRelease -in 2016, 2019) {
WriteLog "Checking for latest .NET Framework feature pack for Windows $WindowsRelease $WindowsSKU"
$Name = """Microsoft .NET Framework 4.8 for Windows 10 Version $WindowsVersion and Windows Server $WindowsRelease for x64"""
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "Latest .NET Framework feature pack saved to $KBPath\$KBFilePath"
}
}
#Search for cached VHDX and skip VHDX creation if there's a cached version
@@ -4672,7 +4749,7 @@ 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) {
if ($WindowsRelease -eq 2016 -and $installationType -eq "Server") {
WriteLog 'WindowsRelease is 2016, adding SSU first'
WriteLog "Adding SSU to $WindowsPartition"
# Add-WindowsPackage -Path $WindowsPartition -PackagePath $SSUFilePath -PreventPending | Out-Null
@@ -4683,8 +4760,17 @@ try {
WriteLog "Removing $SSUFilePath"
Remove-Item -Path $SSUFilePath -Force | Out-Null
WriteLog 'SSU removed'
WriteLog "Adding CU to $WindowsPartition"
}
if ($WindowsRelease -in 2016, 2019, 2021 -and $WindowsSKU -like "*LTSC") {
WriteLog "WindowsRelease is $WindowsRelease and is $WindowsSKU, adding SSU first"
WriteLog "Adding SSU to $WindowsPartition"
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 Cumulative Updates to $WindowsPartition"
# Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath -PreventPending | Out-Null
Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath | Out-Null
WriteLog "KBs added to $WindowsPartition"
@@ -4701,6 +4787,7 @@ try {
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
# Repair-WindowsImage -Path $WindowsPartition -StartComponentCleanup -ResetBase | Out-Null
WriteLog 'Clean Up the WinSxS Folder completed'
} catch {
Write-Host "Adding KB to VHDX failed with error $_"