Worklet: Windows Feature Upgrades via Windows Update Assistant

This Worklet upgrades Windows feature builds using the Windows Update Assistant. It performs an immediate upgrade and does not require the feature build to be available within Automox, nor does it require prerequisite and enablement updates to be pushed first.

Before you use this

Both of these affect whether this Worklet is appropriate for your environment.

  • Scope: this uses the Windows 10 Update Assistant. It upgrades between Windows 10 feature builds. It does not move a device from Windows 10 to Windows 11. Windows 10 has reached end of support, so if your goal is moving devices to Windows 11, use a method intended for that rather than adapting this one.
  • Safeguard holds. The remediation code includes a line that sets DisableWUfBSafeguards. Safeguard holds are how Microsoft blocks a feature update on hardware and software configurations where it is known to cause problems, and Automox otherwise respects them because OS patching is delegated to the native Windows Update Agent. That line is commented out below. Uncomment it only if you intend to deliberately override those holds, and test on a small group first.

Only builds 1803 or later can upgrade using this method. Devices on 1709 or earlier require an in-place ISO upgrade to the desired feature build.

Evaluation Code:

Set $TargetBuild to the build that counts as already upgraded. Devices on that build report compliant, and everything else is flagged for upgrade.

$Version = (Get-CimInstance Win32_OperatingSystem).Version

# The build that counts as "already upgraded":
#   10.0.19044 = 21H2
#   10.0.19045 = 22H2
$TargetBuild = '10.0.19045'

if ($Version -eq $TargetBuild) {
    Write-Output "Already on $Version. No upgrade required."
    exit 0
}

Write-Output "Current build is $Version, target is $TargetBuild. Upgrade required."
exit 2

Build numbers for each release are listed in Microsoft's Windows release information.

Remediation Code:

# Define values in this section
#############################################
$rValue     = '1'          # Enable Target Release Version: 0 = Disabled, 1 = Enabled
$rInfoValue = '22H2'       # Target feature version
$rWindows   = 'Windows 10' # Target product: 'Windows 10' or 'Windows 11'
#############################################

$rPath           = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate'
$rVersion        = 'TargetReleaseVersion'
$rVersionInfo    = 'TargetReleaseVersionInfo'
$rVersionWindows = 'ProductVersion'
$rBlock          = 'DisableWUfBSafeguards'

try
{
    if (-not (Test-Path -Path $rPath))
    {
        New-Item -Path $rPath -Force -ErrorAction SilentlyContinue | Out-Null
    }

    New-ItemProperty -Path $rPath -Name $rVersion -PropertyType DWord -Value $rValue -Force -ErrorAction SilentlyContinue | Out-Null
    New-ItemProperty -Path $rPath -Name $rVersionInfo -PropertyType String -Value $rInfoValue -Force -ErrorAction SilentlyContinue | Out-Null
    New-ItemProperty -Path $rPath -Name $rVersionWindows -PropertyType String -Value $rWindows -Force -ErrorAction SilentlyContinue | Out-Null

    # Uncomment ONLY if you intend to override Microsoft safeguard holds.
    # New-ItemProperty -Path $rPath -Name $rBlock -PropertyType DWord -Value $rValue -Force -ErrorAction SilentlyContinue | Out-Null

    Write-Output "SUCCESS: $rVersion = $rValue, $rVersionInfo = $rInfoValue, $rVersionWindows = $rWindows"
}
catch
{
    $Exception = $error[0].Exception.Message + "`nAt Line " + $error[0].InvocationInfo.ScriptLineNumber
    Write-Error $Exception
    # Registry setting could not be written. The upgrade continues and defaults to the latest version.
}

function Start-Win10UpgradeWUA
{
    <#
.SYNOPSIS
Downloads the Windows Update Assistant and runs it silently.
#>
    [CmdletBinding()]
    param ()

    $DLPath  = "C:\Win10UpgradeTemp"
    $LogDir  = "C:\Win10UpgradeTemp\Logs"

    if (!(Test-Path -Path $DLPath)) { $null = New-Item -ItemType Directory -Path $DLPath -Force }
    if (!(Test-Path -Path $LogDir)) { $null = New-Item -ItemType Directory -Path $LogDir -Force }

    $DLLink      = "https://go.microsoft.com/fwlink/?LinkID=799445"
    $PackagePath = "$DLPath\Win10_WUA.exe"
    $LogPath     = "$LogDir\Win10_WUA.log"

    Remove-Item -Path $PackagePath -Force -ErrorAction SilentlyContinue
    Remove-Item -Path $LogPath -Force -ErrorAction SilentlyContinue

    (New-Object System.Net.WebClient).DownloadFile($DLLink, $PackagePath)

    if (!(Test-Path -Path $PackagePath))
    {
        Write-Output "FAILED: Windows Update Assistant did not download."
        exit 1
    }

    Start-Sleep -Seconds 20

    Write-Output "The upgrade will commence shortly and the device will be rebooted by the Update Assistant."

    Invoke-Expression "$PackagePath /copylogs $LogPath /auto upgrade /dynamicupdate /compat ignorewarning enable /skipeula /quietinstall"
}

Start-Win10UpgradeWUA

User Notifications:

Ensure that Automatic Reboot is disabled for the Worklet, as shown here:


Worklet User Notifications with automatic reboot disabled


Windows Update Assistant uses its own embedded notifications and reboot process, so turning off the Worklet's reboot and notification settings is required for the feature build to stage correctly.

Note: the Update Assistant controls the restart once it is running. The Worklet's automatic reboot must stay disabled so the two do not compete. The restart at the end of the upgrade is the Assistant's, not the Worklet's.

What you will see on the device

When the Worklet runs, a temp directory is staged under C:\Win10UpgradeTemp:

Win10UpgradeTemp directory staged on the device

This is where the Windows Update Assistant files cache before execution. It also contains a log file for troubleshooting. The log is generated after the entire upgrade process completes, so the folder appears empty until the upgrade finishes.

The upgrade itself takes roughly 40 to 60 minutes depending on the device's bandwidth and the build it is starting from. A device on 1803 takes longer than one on 21H1, because it also has to download and install prerequisite enablement packages.

While the upgrade is staging, a background process is visible in Task Manager:

Update Assistant background process in Task Manager

When staging completes, Windows Setup and Windows Installer processes begin:

Windows Setup and Windows Installer processes running

The installer extracts the feature update files into the $GetCurrent and $WINDOWS.~BT folders:

GetCurrent and WINDOWS.BT folders created on the system drive

The $WINDOWS.~BT folder grows as the feature update downloads and extracts its cab files:

WINDOWS.BT folder size increasing during staging

As a reference point, an upgrade from 1903 to 21H2 took about 60 minutes, with $WINDOWS.~BT reaching just under 18 GB. Confirm devices have sufficient free disk space before deploying broadly.

Once staging finishes, Automox shows the update as pending a reboot:

Automox console showing the device pending a reboot

The reboot takes place automatically when the feature upgrade is fully staged:

Device restarting to finalize the feature upgrade

On the next reboot, the device finalizes the feature upgrade:

Windows finalizing the feature upgrade during restart

After the upgrade completes, the user sees this screen at first sign-in:

Post-upgrade welcome screen at first sign-in

Related articles

Was this article helpful?
0 out of 0 found this helpful