Worklet: Automatic OS Upgrade to Windows 10 1903

  • 23 December 2019
  • 11 replies

Userlevel 5

Big shoutout to @aescolastico and @Gen123 for contributing to my previous 1903 OS Upgrade Worklet that made this new automatic 1903 feature update possible!

Automox has the functionality to upgrade Windows OS versions natively through any patch policy. Due to some recent changes made by Microsoft, Automox is unable to discover the Windows 10 version 1903 OS upgrade advertised through Windows Update. Automox engineering is working directly with Microsoft to rectify this issue and expect to support this upgrade natively soon.

It is a one-click automatic upgrade without needing to pre-deploy the 1903 .iso image to your devices. This Worklet will automatically build out the download link for 1903 based on your OS’s architecture, download the .iso image to you local system, mount the .iso to a disk drive, and then automatically run the download setup all silently without any user interaction.

The Evaluation and Remediation code for the Worklet is as follows:


$iso = "C:\programdata\amagent\Windows1903OSUpgrade.iso"

if ((Test-Path $iso) -eq $true)
{Remove-Item $iso

$osversion = (get-itemproperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId

if (($osversion -lt "1903"))
{exit 1
{exit 0


$lang = "English"
$locID = "en-US"
$verID = "Windows10ISO"
$skuID = "8829"
$prodID = "1384"
$archID = "IsoX64"
## variables you might not want to change (unless msft changes their schema)
$pgeIDs = @("a8f8f489-4c7f-463a-9ca6-5cff94d8d041", "cfa9e580-a81e-4a4b-a846-7b21bf4e2e5b")
$actIDs = @("getskuinformationbyproductedition", "GetProductDownloadLinksBySku")
$hstParam = ""
$segParam = "software-download"
$sdvParam = "2"
## used to spoof a non-windows web request
$userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362"
## used to maintain session in subsequent requests
$sessionID = [guid]::NewGuid()
## builds session request url
$uri = "" + $locID + "/api/controls/contentinclude/html"
$uri += "?pageId=" + $pgeIDs[0]
$uri += "&host=" + $hstParam
$uri += "&segments=" + $segParam + "," + $verID
$uri += "&query="
$uri += "&action=" + $actIDs[0]
$uri += "&sessionId=" + $sessionID
$uri += "&productEditionId=" + $prodID
$uri += "&sdvParam=" + $sdvParam
## requests user session
Invoke-WebRequest -UserAgent $userAgent -WebSession $session $uri -ErrorAction:Stop -Method:Post -Headers $headers -UseBasicParsing | Out-Null
## builds link request url
$uri = "" + $locID + "/api/controls/contentinclude/html"
$uri += "?pageId=" + $pgeIDs[1]
$uri += "&host=" + $hstParam
$uri += "&segments=" + $segParam + "," + $verID
$uri += "&query="
$uri += "&action=" + $actIDs[1]
$uri += "&sessionId=" + $sessionID
$uri += "&skuId=" + $skuID
$uri += "&lang=" + $lang
$uri += "&sdvParam=" + $sdvParam
## requests link data
$response = Invoke-WebRequest -UserAgent $userAgent -WebSession $session $uri -ErrorAction:Stop -Method:Post -Headers $headers -UseBasicParsing
## parses response data
$objs = $response.Links
$objs | Foreach-Object {$_.href = ($_.href).Replace('amp;','')}
$linky = $objs | Select-Object -Property href | Sort-Object -Property href
$link = $linky | Select-Object -ExpandProperty href
## Determine correct link for OS Architecture
$osarch = (Get-WmiObject Win32_OperatingSystem).OSArchitecture
If ($osarch -eq "64-bit") {
$dllink = $link | Where-Object {$_ -match 'x64.iso'}
} elseif ($osarch -eq "32-bit") {
$dllink = $link | Where-Object {$_ -match 'x32.iso'}
Write-Output $dllink
Try {
(new-object System.Net.WebClient).DownloadFile("$dllink", "C:\programdata\amagent\Windows1903OSUpgrade.iso") |
Out-file C:\Windows\Temp\output.csv -Append
} Catch {
Write-Error ".iso linked was successfully created but download Failed. Reference c:\windows\temp\output.csv for more information or contact Automox Support"
exit 1
#specify path to ISO image
#############Change the settings in this block#######################
$isoImg = "C:\programdata\amagent\Windows1903OSUpgrade.iso"
Mount-DiskImage -ImagePath $isoImg
$letter = (Get-DiskImage $isoImg | Get-Volume).DriveLetter
$dos = ":" ### Unnecessary with changed line below
$drivemount = "$letter" + "$dos"
Set-Location $drivemount

# Required: The drive letter needs to be manually changed to match the value of $driverletter (ex: Y:)

# Optional: /pkey is for a device that needs a product key. Default is disable, remove "#" to enable. (ex: /pkey XXXXX-XXXXX). Not required for install

# Optional: /noreboot is enabled by default. Remove "#" to automatically reboot the device after install is complete

./setup.exe /auto upgrade /quiet #/pkey

The Evaluation code exits with a 1 if a devices OS version is less than 1903 and executes the policy at the scheduled time

Choose the setup.exe arguments you want when it performs the OS update. This is the last line of code in the Remediation block. By Default it is set to do a quiet install and automatically reboot the device to complete the upgrade.

Here is an example of the setup.exe command using the /quiet and /noreboot argument:

Copy to clipboard

.\setup.exe /auto upgrade /quiet /noreboot

That should do it! Be sure to test this on a few devices before deploy to production environment.

Let me know if there are any questions!

  1. Here is a list of other optional switches you can use in the install command. You just need to add them with a “/’ in front, like the other switches:

  • Switch: /showoobe - Action: When /showoobe is set to Full, the end user must interactively complete OOBE. Alternatively, when /showoobe is set to None, OOBE is skipped and components are set to their default settings. Example: setup.exe /auto upgrade /showoobe full

  • Switch: /DynamicUpdate - Action: Specifies whether setup will perform Dynamic Update operations (search, download, and install updates). Example: setup.exe /auto upgrade /DynamicUpdate disable

  • Switch: /Postoobe Path\setupcomplete.cmd - Action: Injects setupcomplete.cmd file from the specified location. Setupcomplete.cmd is a customized script to perform tasks after the installation completes but before first user login. It is run with System privileges. Example: setup.exe /auto upgrade /postoobe c:\script\setupcomplete.cmd

  • Switch: /PBRUpdate - Action: When /PBRUpdate is set to Enable, setup will update or create the PBR partition. Conversely, when /PBRUpdate is set to Disable, setup will not update or create the PBR partition. Example: setup.exe /auto upgrade /PBRupdate disable

  • Switch: /migratealldrivers - Action: When /migratealldrivers is set to All, setup will attempt to migrate all drivers as part of the installation. In contrast, when /migratealldrivers is set to None, setup will not migrate any drivers as part of the installation. NOTE: this switch should only be used in testing and test envoriments.It should not be used in production. Example: setup.exe /auto upgrade /migratealldrivers none

  • Switch: /installdrivers - Action: Setup will inject all driver.infs found in the specified location during the installation process. Setup will recursively search through all the subfolders of the specified location. Example: setup.exe /auto upgrade /installdrivers c:\myUpgrade\drivers

  • Switch: /copylogs - Action: Upon failure, setup will copy or upload compressed logs to the specified location. Please note that the PC and /or user must have permission and network access to the specified file path. This command runs in the system context so may not have permissions to copy to locations that require user permissions. Example: setup.exe /auto upgrade /copylogs \MyShare\UpgradeLogs

  • Switch: /Telemetry - Action: When /Telemetry is set to Enable, setup will collect and upload telemetry generated by the installation. However, when /Telemetry is set to Disable, setup will not collect and upload installation – related telemetry. Example: setup.exe /auto upgrade /Telemetry enable

That should do it! Be sure to test this on a few devices before deploy to production environment,

Let me know if there are any questions!

11 replies

Hello! This Works right up to the actual install for me. It downloads the ISO, Mounts it and then when it comes to run the setup it just falls over. No errors to try and fault find either. I tried to run the setup Manually Via powershell to see if any errors appear and it runs fine. I also tried removing the /quiet /noreboot as someone had an issue with the previous version of this worklet. any help would be greatly appreciated!

Userlevel 7

Thanks for letting us know @AdamGourlay. The worklet author, @awhitman, is looking into this issue and will post here when he has something to report. He said he has another customer having the same issue, so there might be something in the worklet code he needs to fix for certain cases.

Userlevel 5

Hey @AdamGourlay

Sorry this isn’t working for you. If you run the script locally on the device without the /quiet option, does the setup.exe run at all? If that isn’t working try running the whole script locally without the /auto upgrade argument, so just the setup.exe.

Reach out to me directly with the results:

Hi @awhitman

I sent over a few screen shots of my results and a some other findings.

Hope they were useful.


Userlevel 5

After working directly with @AdamGourlay it has came to my attention that the mounting of the iso to an available drive letter is not working for everyone. The code is designed to choose an open drive letter that is available to the device used for the iso disk partition.

The error will look like this if you run the script locally on the device using Powershell:

If you see this error, this means the mount failed. To get around this, use the code below and manually enter the drive letter you want to use. It needs to be a letter that is currently not being utilized in a partition of the disk.

$isoImg = "C:\Windows\Temp\Windows10OSUpgrade.iso"


$driveLetter = "Y:"
$diskImg = Mount-DiskImage -ImagePath $isoImg -NoDriveLetter
$volInfo = $diskImg | Get-Volume
mountvol $driveLetter $volInfo.UniqueId

Y:\setup.exe /auto upgrade /quiet /noreboot

The way it is written above, it will create the disk partition using the “Y:” drive. If you want to use a different letter, you’ll need to update it both for $driveLetter = "Y:" and the “Y:” in the setup command, Y:\setup.exe /auto upgrade /quiet /noreboot.

Replace this at the bottom part of your Worklet code to handle the mounting of the iso, and the running of the setup.exe.

Let me know if you have any questions!

Hi @awhitman,

I did some more testing and ran into an issue.

When the script got to the $volInfo = $diskImg | Get-Volume it wouldn’t actually assign anything to $VolInfo because the previous tag also didn’t have anything assigned.

To fix this it needed -Passthru adding onto the end of $diskImg = Mount-DiskImage -ImagePath $isoImg -NoDriveLetter

The final script looks like this:

$driveLetter = “Y:”

$diskImg = Mount-DiskImage -ImagePath $isoImg -NoDriveLetter -Passthru

$volInfo = $diskImg | Get-Volume

mountvol $driveLetter $volInfo.UniqueId

Y:\setup.exe /auto upgrade /quiet

I also found that /Noreboot doesn’t work anymore even though microsoft say it should…


Userlevel 5

@AdamGourlay Very nice! thanks for working out the logic.

Userlevel 5

Some enhancements have been made to the 1903 upgrade Worklet. These include the following:

  1. Automatic removal of the 1903 .iso image once upgrade has been completed

  2. Automatic drive letter assignment to image disk mount.

These enhancements are aimed to make the script fully automated without any user or admin interaction once the policy is created, and scheduled.

The code above has already been edited to reflect these enhancements.

Userlevel 4

Thanks for an excellent Worklet. I’m new to Automox and this worklet was the first one I attempted to use. It was easy to deploy and works as advertised. It really speeds up the turn around for our users to access the devices for work.

Userlevel 5

Thanks Mark for the feedback!

Glad it worked well for you without any errors! It’s great that it is providing value by saving you time, and providing an easy way to update your OS!

Thank you so much for writing this. Those creator updates can cause such headaches and hours of extra work for me and my team. I appreciate this more than i can express in words.