Feature Update issue
Hi Michael,
it seems the latest feature update to 24h2 will be downloaded which stuck the update process during Autopilot. Did try some exclusion options but no one was working.
Maybe you´ve an idea to implement a workaround. UpdateOS.log
thx & regards, Harald
if we add following entry - if ($.Title -notmatch "24H2") { [void]$WUUpdates.Add($) } the 24h2 update is not getting downloaded, but also the latest CU from current month not
One way of solving it may be to use the 1.6 version of the script which included the PS Modules, and use the hide option IE:
Opt into Microsoft Update
Add-WUServiceManager -ServiceID "7971f918-a847-4430-9279-4a52d1efe18d" -AddServiceFlag 7 -Confirm:$False
Install all available updates
$ts = get-date -f "yyyy/MM/dd hh:mm:ss tt" Write-Host "$ts Installing updates."
#Hide 24H2 KB hidelist format "kbxxx","kbxxx" $HideList="KB5044284" Get-Windowsupdate -KBArticleID $hidelist -Hide -AcceptAll
Install-WindowsUpdate -NotTitle "preview" -AcceptAll -IgnoreReboot -Verbose | Select Title, KB, Result | Format-Table $needReboot = (Get-WURebootStatus -Silent).RebootRequired
Instead of the hidelist, you may also just include the -NotKBArticleID variable in install-windowsupdate.
Like:
Install-WindowsUpdate -NotKBArticleID KB5044284 -NotTitle "preview" -AcceptAll -IgnoreReboot -Verbose | Select Title, KB, Result | Format-Table
$needReboot = (Get-WURebootStatus -Silent).RebootRequired
I'm not experienced in Powershell, but it worked for us at least.
@JanVidarA we already tried several variations - if we add -NotKBArticleID KB5044284 -NotTitle "preview" we only get updates for Defender and not the latest CU. Btw KB5044284 ist not the "Windows 11, version 24H2" upgrade
@hacklhar, this is the v1.6 script I'm using. It installs "everything" except for the 2024-10 update KB5044285, and some minor defender updates which comes afterwards. I'm satisfied with that, as it doesn't affect user too much. There's an option to install specific KBs also, although I haven't tried it myself.
https://powershellisfun.com/2024/01/19/using-the-powershell-pswindowsupdate-module/
says something about that. Adding
Install-WindowsUpdate -KBArticleID KB5044285
Might solve it. I don't know. That's all I got :-)
Install command for win32 app: powershell.exe -noprofile -executionpolicy bypass -file .\UpdateOS.ps1 -Reboot Hard
...
<#PSScriptInfo
.VERSION 1.6
.GUID 07e4ef9f-8341-4dc4-bc73-fc277eb6b4e6
.AUTHOR Michael Niehaus
.COMPANYNAME Microsoft
.COPYRIGHT
.TAGS Windows AutoPilot Update OS
.LICENSEURI
.PROJECTURI
.ICONURI
.EXTERNALMODULEDEPENDENCIES
.REQUIREDSCRIPTS
.EXTERNALSCRIPTDEPENDENCIES
.RELEASENOTES Version 1.6: Default to soft reboot. Version 1.5: Improved logging, reboot logic. Version 1.4: Fixed reboot logic. Version 1.3: Force use of Microsoft Update/WU. Version 1.2: Updated to work on ARM64. Version 1.1: Cleaned up output. Version 1.0: Original published version.
#>
<# .SYNOPSIS Installs the latest Windows 10/11 quality updates. .DESCRIPTION This script uses the PSWindowsUpdate module to install the latest cumulative update for Windows 10/11. .EXAMPLE .\UpdateOS.ps1 #>
[CmdletBinding()] Param( [Parameter(Mandatory=$False)] [ValidateSet('Soft', 'Hard', 'None', 'Delayed')] [String] $Reboot = 'Soft', [Parameter(Mandatory=$False)] [Int32] $RebootTimeout = 120 )
Process {
If we are running as a 32-bit process on an x64 system, re-launch as a 64-bit process
if ("$env:PROCESSOR_ARCHITEW6432" -ne "ARM64") { if (Test-Path "$($env:WINDIR)\SysNative\WindowsPowerShell\v1.0\powershell.exe") { & "$($env:WINDIR)\SysNative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy bypass -NoProfile -File "$PSCommandPath" -Reboot $Reboot -RebootTimeout $RebootTimeout Exit $lastexitcode } }
Create a tag file just so Intune knows this was installed
if (-not (Test-Path "$($env:ProgramData)\Microsoft\UpdateOS")) { Mkdir "$($env:ProgramData)\Microsoft\UpdateOS" } Set-Content -Path "$($env:ProgramData)\Microsoft\UpdateOS\UpdateOS.ps1.tag" -Value "Installed"
Start logging
Start-Transcript "$($env:ProgramData)\Microsoft\UpdateOS\UpdateOS.log"
Main logic
$needReboot = $false
Load module from PowerShell Gallery
$ts = get-date -f "yyyy/MM/dd hh:mm:ss tt" Write-Host "$ts Importing NuGet and PSWindowsUpdate" $null = Install-PackageProvider -Name NuGet -Force $null = Install-Module PSWindowsUpdate -Force Import-Module PSWindowsUpdate
Opt into Microsoft Update
Add-WUServiceManager -ServiceID "7971f918-a847-4430-9279-4a52d1efe18d" -AddServiceFlag 7 -Confirm:$False
Install all available updates
$ts = get-date -f "yyyy/MM/dd hh:mm:ss tt" Write-Host "$ts Installing updates."
#Hide 24H2 KB hidelist format "kbxxx","kbxxx" $HideList="KB5044284" Get-Windowsupdate -KBArticleID $hidelist -Hide -AcceptAll
Install-WindowsUpdate -NotTitle "preview" -AcceptAll -IgnoreReboot -Verbose | Select Title, KB, Result | Format-Table $needReboot = (Get-WURebootStatus -Silent).RebootRequired
Specify return code
$ts = get-date -f "yyyy/MM/dd hh:mm:ss tt" if ($needReboot) { Write-Host "$ts Windows Update indicated that a reboot is needed." } else { Write-Host "$ts Windows Update indicated that no reboot is required." }
For whatever reason, the reboot needed flag is not always being properly set. So we always want to force a reboot.
If this script (as an app) is being used as a dependent app, then a hard reboot is needed to get the "main" app to
install.
$ts = get-date -f "yyyy/MM/dd hh:mm:ss tt" if ($Reboot -eq "Hard") { Write-Host "$ts Exiting with return code 1641 to indicate a hard reboot is needed." Stop-Transcript Exit 1641 } elseif ($Reboot -eq "Soft") { Write-Host "$ts Exiting with return code 3010 to indicate a soft reboot is needed." Stop-Transcript Exit 3010 } elseif ($Reboot -eq "Delayed") { Write-Host "$ts Rebooting with a $RebootTimeout second delay" & shutdown.exe /r /t $RebootTimeout /c "Rebooting to complete the installation of Windows updates." Exit 0 } else { Write-Host "$ts Skipping reboot based on Reboot parameter (None)" Exit 0 }
}
@JanVidarA thanks for providing your version of ps, but it still is not loading the latest CU for 23H2. No clue what´s going wrong
@mtniehaus do you have any suggestions to prevent the Feature Update 24H2 from being installed which gets us stuck in ESP?
on version 1.10, I changed the part that sets the criteria to avoid titles containing "24H2" to avoid update to 24h2.
$WUUpdates = New-Object -ComObject Microsoft.Update.UpdateColl
$ts = get-date -f "yyyy/MM/dd hh:mm:ss tt"
Write-Host "$ts Getting $_ updates."
((New-Object -ComObject Microsoft.Update.Session).CreateupdateSearcher().Search($)).Updates | ForEach-Object {
if (!$.EulaAccepted) { $.AcceptEula() }
if ($.Title -notmatch "Preview" -and $.Title -notmatch "24H2")
{ [void]$WUUpdates.Add($) }
So you guys experienced the tool doing feature upgrades? Regarding this issue, https://github.com/mtniehaus/UpdateOS/issues/9, it should never do feature upgrades. Thank you for clarification.
@swissbuechi we encounter issues that we get the feature update for 24H2 offered each time we are running UpdateOS
@swissbuechi we encounter issues that we get the feature update for 24H2 offered each time we are running UpdateOS
@hacklhar Thank you for clarification. I have the requirement to completely disable the installation of any feature upgrades. I'll try to implement this and report it back here if I succeed.
@swissbuechi
By filtering on CategoryID you can block Feature Updates (Feature Updates use CategoryID 3689BDC8-B205-4AF4-8D4A-A63924C5E9D5). I think this is a cleaner approach than trying to filter on title. The below snippet fixes issue #9.
I do not have experience working with COM objects, so there is likely a much more optimized way to do this. Some updates may be a member of multiple categories, so I have included logic to account for that. This snippet additionally includes a logic check for the 'EulaAccepted' property as requested in issue #12.
$queries | ForEach-Object {
$WUUpdates = New-Object -ComObject Microsoft.Update.UpdateColl
$TimeStamp = get-date -f "yyyy/MM/dd hh:mm:ss tt"
Write-Host "$TimeStamp Getting $_ updates."
$CandidateUpdates = ((New-Object -ComObject Microsoft.Update.Session).CreateupdateSearcher().Search($_)).Updates
ForEach ($CandidateUpdate in $CandidateUpdates) {
If ($CandidateUpdate.Title -notmatch "Preview") {
If ($CandidateUpdate | Get-Member EulaAccepted) { if (!$CandidateUpdate.EulaAccepted) { $CandidateUpdate.AcceptEula() } }
ForEach ($CandidateUpdateCategory in $CandidateUpdate.Categories) {
if ($CandidateUpdateCategory.CategoryID -ne "3689BDC8-B205-4AF4-8D4A-A63924C5E9D5" -and $CandidateUpdate -notin $WUUpdates) { [void]$WUUpdates.Add($CandidateUpdate) }
}
}
}
I've added logic to do this in version 2.1.