Prompting Users to Start an In-Place Upgrade


A couple of years back I had a customer that wanted to prompt users to run a Windows 10 in-place upgrade. Although the customer knew they’d have to force the upgrade at a certain point, they wanted to give the end users an opportunity to run the upgrade on their schedule to minimize impact.

What we came up with was a PowerShell script that would pop up a UI for the end user prompting them to either snooze or upgrade. The upgrade button would open Software Center to the OS page where the user could then click to start the task sequence.

This early version required manually defining the deadline, etc. in the script package, had no checks for the device having the upgrade deployment, and so on. The only check built into the early version was the script would check if the upgrade was already complete and if so, would close without displaying to the end user.

Our design choice for that first version was a bit tongue in cheek and we got a few laughs from it.

Fast forward to early this year and I have multiple customers racing the clock to get 1909 upgraded. Almost every single one raised the same concern about interrupting users and trying to get the users to initiate the upgrade when convenient for them. I remembered the old script and dug it out of my code repository.

My current customers are not as free to have the lighthearted version with Clippy, necessitating a change to a more professional prompt.

While I was updating the UI, I experienced major scope creep and ended up adding a lot of functionality.

Added in v2:

  • Checks that the device has an active policy for the task sequence
  • Finds the first deadline for the task sequence, even if the device has multiple deployments of the TS
  • When user clicks upgrade, Software Center opens AND the TS is initiated
  • If you set the switch for pre-caching content, the status of the download is displayed in UI
  • UI displays the next run time
  • Strings are now configurable in the settings file, no need to modify the script itself
  • Window title bar is hidden to prevent closing without choosing upgrade or snooze
  • Window is always on top and cannot be moved from the center of the screen
  • Optional: User clicking snooze or upgrade now is saved as an instance of a custom WMI class that can be inventoried, allowing you to see the run history should a user say they did not get enough prompts before the upgrade was forced.

Changing the logo is as easy as replacing the logo.jpg file in the source directory.


NOTE: If you are using different TSes for different sets of devices, you will need separate packages of the reminder for each.

Create a package containing the source files

The cmdline for the program is:
cmd /c start /min “” powershell.exe -ExecutionPolicy Bypass -File “.\IPU.ps1” -windowstyle hidden

Set the program to run “Normal”

Make sure the program will only run when a user is logged in, it runs with admin rights, and allows users to interact with the deployment

Before distributing the content you will need to put your logo in place. Put it in the folder named as logo.png and if you want the taskbar icon to reflect your branding as well, you can also add a favicon.ico.

Now edit settings.xml to configure the script.

NOTE: Make sure you set the correct TS ID.

<?xml version="1.0"?>
<?xml-stylesheet type='text/xsl' href='style.xsl'?>
        <Title>Windows 10 20H2 Upgrade</Title>
        <Greeting>This computer requires a Windows 10 upgrade.</Greeting>
        <Note1>You may choose to delay this upgrade for now. Once the deadline is reached, you will no longer be able to postpone.</Note1>
        <Note2>Once the upgrade starts you will not be able to use the computer for approximately 90 minutes, longer if the files are not yet downloaded**.</Note2>
        <Choice>What would you like to do?</Choice>
        <UpgradeButton>Upgrade Now</UpgradeButton>
        <PreCache>**ReplaceX of ReplaceY referenced items downloaded</PreCache>
        <deadline>The Upgrade will become mandatory on </deadline>
        <reminder>*Next reminder at approximately </reminder>

If you have questions on which string is which in the UI, you can reference “UI Settings.png”

Now you can distribute content for the package and deploy to devices.

When deploying, set the program to Always Rerun and set the schedule to how often you want to prompt the users.

NOTE: The reminder opens on the schedule set, NOT a delay from the user hitting snooze.
Example: If the reminder is set to run every hour on the hour and the user is away and does not see the prompt or hits snooze until 9:55, the next run will still happen 5 minutes later.

If the reminder window is still open when the next run time happens, the new instance will close the existing instance so that the next run time (or any other updates) will be reflected.

If you choose to enable the inventory option, the entries are saved to root\cimv2:IPU_Reminder. You will need to add the class to your hardware inventory. At this point I have not made any reports to display the information, I have just used Resource Explorer.


To make the upgrade now button start the task sequence, it must run as the user. However, to get the WMI info needed, the script must run as an admin. To make this all function I am using Kelvin Tegelaar’s RunAsUser PowerShell module.

The Files