Worklet: Automatic Upgrade of Devices to Windows 10 version 1903

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.

Until this time I have created a Worklet to handle upgrades to Windows 10 version 1903. In a single click, this Worklet can update all of your Windows 10 1809 devices to version 1903 all silently without any end-user interaction required! This will give you the confidence that all of your devices are at the latest Windows 10 version.

Safety First
This Worklet does perform an OS upgrade silently to devices so ensuring everything is in order before pushing the button is important to ensure you have a positive experience when running these OS upgrades. Keep the following in mind:

  • Test, test, and test more. This upgrade happens silently and if something is misconfigured in the Worklet, or in the iso image, then it could cause issues on the device when the upgrade takes place. Get a Windows 10 VM on a previous version and run the Worklet and analyze the results. This will build your confidence when it’s time to run this on 100’s of production Windows devices.
  • Ensure the device meets the system requirements for the upgrade. If most devices are running Windows 10 already, then they should be good to upgrade to 1903. However, this script does not include system checks so be sure it’s something you keep in mind
  • This is designed to perform the upgrade silently and even reboot the device to complete the installation. It would be a best practice to inform users of the upgrade.
  • Measure twice, cut once. Double check everything before deploying this Worklet.

Instructions:
Carefully follow the instructions below to ensure the upgrade happens successfully.

  1. Deploying the Windows 10 1903 ISO file. The way the script is designed today, the ISO file must already exist on the device before running the Automox Worklet. I am looking at ways to automatically download the ISO from the Worklet so it can literally be a “One-Click” installation Worklet. Until this time, the ISO must manually be put on the device. To download it, go to the Microsoft website. I can also send it to you for both x64 and x32 bit if you provide me a link to a repository. This Worklet will work for both 32-bit and 64-bit architectures, just be sure to download the correct ISO for your OS.

  2. Place the ISO on the devices you want to upgrade. You will need to know the directory path of the ISO for the Worklet, so be sure to note it somewhere.

  3. Once the ISO is in the desired directory on all the devices you want to run the 1903 upgrade on, the Worklet can do the rest.

  4. Copy and paste both the Evaluation and Remediation code below to the new Worklet in your Automox console.

Evaluation:

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

if (($osversion -eq "1903"))

{exit 0}

       else

{exit 1}

Remediation:

####################################################################################################################################################################

#specify path to ISO image (ex:"C:\Windows\Win10_1903_V2_English_x64.iso")

$isoImg="C:\Users\Adam Whitman\Win10_1903_V2_English_x64.iso"

# Drive letter - use desired drive letter (ex: Y:)

$driveLetter = "Y:"

####################################################################################################################################################################

#SCRIPT BLOCK

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

$volInfo = $diskImg | Get-Volume

mountvol $driveLetter $volInfo.UniqueId

# 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

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

Evaluation - evaluates to see the current OS version. Runs remediation if anything other then 1903 is the current version. If 1903 is the current version already, evaluation exits 0 (compliant).

Remediation - Interacts with the ISO on the device to perform the upgrade to 1903.

  1. You will need to change some REQUIRED values in the remediation code specific to your environment. These include:
  • Where it says “$isoImg=” you need to put your specific ISO file path noted earlier. This needs to be exact in order for the Worklet to find the ISO and mount it to a drive. And example of this is already included for my system in the remediation code. (ex: “C:\Windows\Win10_1903_V2_English_x64.iso”)
  • Where is says “$driveLetter=” you can change the drive letter if you desire. I have “Y:” as an example and most of the time this is the best option. However, you can change it if you desire. Be sure to test it out first!
  • The last required value is inputting the drive letter you have in “$driveLetter=” at the beginning of the final command in the remediation code, (Y:\setup.exe /auto upgrade /quiet #/noreboot #/pkey) This will ensure it references the drive the ISO is mounted to.
  1. The above options are required. The command switches are all OPTIONAL. I included a few of these in the remediation command that I find are the most important to configure. This includes:
  • /pkey - this is for a device that needs a product key. Default is disable, remove “#” to enable. (ex: /pkey XXXXX-XXXXX). Not required for install.
  • /noreboot - is enabled by default. Remove “#” to automatically reboot the device after install is complete.
  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
  1. You should now be set to Save the Worklet and assign it to your devices. You can either execute it manually or run it on a schedule. This does happen silently and takes some time, so be patient when testing as you will not see your computer doing anything during the upgrade install. Reboot is required on the device to fully apply the upgrade, and TEST, TEST, TEST!

As always if you have any questions feel free to hit me up!

1 Like

Hi Adam, Nic,

See below the code that I used to download the ISO file.

First, I have created the ISO with the MS media tool, upload it to a web server and also create an output file to confirm that the file has been downloaded correctly:


$Save_Dir = "c:\\temp"

if (-not (Test-Path $Save_Dir)) {
        New-Item -Path $Save_Dir -ItemType directory
} else {}

function Copy_1903_ISO {
    #############Change the settings in this block#######################
    $output   = "C:\temp\output.csv"
    ### Change the URL from where to download the ISO file created with the MS Media Creation tool
    $URL = "http://xxxx/Windows1903.iso"
    ######################################################################
    "Starting download"| Out-File $output -Append
    
    Try {
        (new-object    System.Net.WebClient).DownloadFile("$URL", "$Save_Dir\Windows1903.iso")
		"Download Complete"| Out-File $output -Append
        exit 0
    }
    Catch {
    	"Download Complete"| Out-File $output -Append
        exit 1
    }
	
}


Copy_1903_ISO

Then, I did some changes to your worklet to do the silent upgrade since the one that you posted does not work for me:


#############Change the settings in this block#######################
$isoImg="C:\temp\Windows1903.iso"
##############################################################

mount-DiskImage -ImagePath $isoImg
$letter = (Get-DiskImage $isoImg | Get-Volume).DriveLetter

$dos = ":"
cd $letter$dos

    Try {
        ## I have removed the /quite and the /noreboot as it was not working in my environment.
        .\setup.exe /auto upgrade
	exit 0
    }
    Catch {
        exit 1
    }

Thanks

1 Like

Thanks for sharing your improvements @Gen123!

This looks great! I wanted to incorporate the download of the iso in the script which looks like is accomplished using this. Great work!

Thanks @awhitman @Nic!

If you’re looking for a way to download the iso without staging it on a server somewhere this script I wrote may help. Unfortunately I cant test it in a worklet ( company I work at doesnt use automox :disappointed: )

## .SYNOPSIS

## This script generates a fresh download link for a windows iso

## .OUTPUTS

## Win10 download link

## .NOTES

## Version: 1.0

## Author: Andy Escolastico

## Creation Date: 10/11/2019

## variables you might want to change

$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 = "www.microsoft.com"

$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 = "https://www.microsoft.com/" + $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

$null = Invoke-WebRequest -UserAgent $userAgent -WebSession $session $uri

## builds link request url

$uri = "https://www.microsoft.com/" + $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

## parses response data

$raw = ($response.AllElements | Where-Object {$_.tagname -eq "input"}).value

$json = $raw.Replace(',"DownloadType": IsoX64',',"DownloadType": "IsoX64"')

$json = $json.Replace(',"DownloadType": IsoX86',',"DownloadType": "IsoX86"')

$objs = $json | ConvertFrom-Json

$objs | Foreach-Object {$_.Uri = ($_.Uri).Replace('amp;','')}

## stores download link

$dlLink = $objs | Where-Object {$_.DownloadType -eq $archID} | Select-Object -ExpandProperty Uri

## outputs download link

Write-Output $dlLink
1 Like

That’s fantastic, thanks for sharing your script!

Wow! this is great!

Thanks for sharing this!