Create a Custom Splash Screen for a Windows 10 In-Place Upgrade

A while back I wrote a blog with some scripts that can be used to improve the user experience in a Windows 10 in-place upgrade. The solution included a simple splash screen that runs at the beginning of the upgrade to block the screen to the user and discourage interaction with the computer during the online phase of the upgrade. Since then, I made some improvements to the screen and styled it to look more like the built-in Windows update experience in Windows 10. Using this splash screen not only discourages computer interaction during the upgrade, but also creates a consistent user experience throughout the upgrade process, for a user-initiated upgrade.

The updated screen contains an array of text sentences that you can customise as you wish. Here is an example of what it could look like:

The splash screen is not completely foolproof in that it is still possible to use certain key combinations, like ctrl-alt-del and alt-tab etc, but the mouse cursor is hidden and mouse buttons will do nothing. The intention is simply to discourage the user from using the computer during the online phase. If the computer is locked, it will display the splash screen again when unlocked. If you wish to block user interaction completely, you might consider a more hardcore approach like this or this.

To use the splash screen, download all the files in my GitHub repository here (including the bin directory). Create a standard package in ConfigMgr containing the files (no program needed) and distribute. Then add a Run PowerShell Script step in the beginning of your in-place upgrade task sequence that looks like the following (reference the package you created):


Once the splash screen has been displayed, the task sequence will move on to the next step – the screen will not block the task sequence.

How does it work?

The Invoke-PSScriptAsUser.ps1 simple calls the Show-OSUpgradeBackground.ps1 and runs it in the context of the currently logged-on user so that the splash screen will be visible to the user (task sequences run in SYSTEM context so this is necessary).

The Show-OSUpgradeBackground.ps1 determines your active screens, creates a runspace for each that calls PowerShell.exe and runs the Create-FullScreenBackground.ps1 for each screen.

The Create-FullScreenBackground.ps1  does the main work of displaying the splash screen. It will hide the task bar, hide the mouse cursor and display a full screen window in the Windows 10 update style. I’ve used the excellent MahApps toolkit to create the progress ring. The text displayed in the screen can be defined by placing short sentences in the $TextArray variable. The dispatcher timer will cycle through each of the these every 10 seconds (or whatever value you set) ending with a final sentence “Windows 10 Upgrade in Progress” which will stay on the screen until the computer is restarted into the next phase of the upgrade.

You can test the splash screen before deploying it simply by running the Show-OSUpgradeBackground.ps1 script.

Remember to deselect the option Show task sequence progress in the task sequence deployment to avoid having the task sequence UI show up on top of the window.

30 thoughts on “Create a Custom Splash Screen for a Windows 10 In-Place Upgrade

  1. Hi Trevor, thanks for this! I was wondering, if no one is logged into the machine and the TS runs this script, will the splash screen show up when someone logs in? I ask because with 1803 it does a lot more stuff in online mode, which means it takes longer before the offline stuff happens. In my TS there are BIOS updates that would run after the splash screen starts, which would reboot the computer, and then the user may try to log back in after that.

    1. Hi Chris, in that scenario the splash screen won’t display as it requires a user context to run in. It’s only really intended for a user-initiated upgrade. It would be nice to be able to handle the ‘no user logged in’ scenario as well though – hopefully MS can make some improvements in this area.

    2. Chris, you can add in a check in your task sequence step to see if Explorer is running, if not then the splash screen won’t be initialized. Add WMI query: Select __relpath FROM Win32_Process WHERE Caption=’explorer.exe’

  2. Assuming like every other IPU GUI out there this is intended for Win10 to Win10 because it does nothing on a Win7 machine.

      1. Thanks. I’ve tested installing WMF 5.1 on Win7 and the GUI works fine. So i’ll need to get this out before our upgrade..maybe even as part of the IPU task sequence.

    1. Daniel, be very careful with WMF 5.1. I had that on systems a year ago and the IPU would fail every time. I don’t remember the exact issue anymore but it was a known bug that I don’t think has been fixed. You would be better off with using WMF 5.0.

  3. We’ve taken your solution one step further here at NSW DoE and extended it into both WinPE phases of our W10 IPU (we inject drivers via a WebService hence WinPE) and also the post upgrade phase as W10 runs through it’s final checks…

    We’ve duplicated the initial solution and renamed the scripts so we can directly call (without “Invoke-PSScriptAsUser” since we’re not in a user session) a new “Show-WinPEBackground” during WinPE, and then after a reboot as W10 comes online, we call “Show-OSFinalBackground”. We’ve also edited the status messages in the $TextArray to represent the phase we’re in to the user. We now have consistent user experience from end-to-end.

    It’s a thing of beauty, and it’s all your fault 🙂

      1. Hi Rafal,

        You don’t need a separate script or ServiceUI.exe within WinPE – just add a powershell script step in your task sequence and call “Show-OSUpgradeBackground.ps1”. Because we are in WinPE, you’re not running within a user context, so you don’t need to call “Invoke-PSScriptAsUser.ps1” first.

  4. Hi Trevor,

    This is great Thanks for sharing!!

    Andy, Would share your IPU TS? Very interested to see how you got this working after the first reboot.


  5. Hi

    This seems to have stopped working now. When running the Invoke-PSScriptAsUser I get the error…

    Exception calling “StartProcessAsCurrentUser” with “2” argument(s): “StartProcessAsCurrentUser: GetSessionUserToken
    At C:\Users\xxx\Downloads\CustomW10UpgradeSplashScreen-master\Invoke-PSScriptAsUser.ps1:286 char:1
    + [Runasuser.ProcessExtensions]::StartProcessAsCurrentUser(“$env:windir …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : Exception

  6. Hi,

    I’m confused and hope you can help me. Andy said he is using the “Show-OSUpgradeBackground.ps1” after the reboot. How? I have no chance to start the splash screen visible in the logon mask, so without a logged on user. 😦

    Thanks in advance


  7. Hi,
    I haved tryed this from Win10 x64 v1511, v1607 and v1709 but all get the same error:

    Exception calling “StartProcessAsCurrentUser” with “2” argument(s): “StartProcessAsCurrentUser: GetSessionUserToken
    At ……………..\Invoke-PSScriptAsUser.ps1:286 char:1
    + [Runasuser.ProcessExtensions]::StartProcessAsCurrentUser(“$env:windir …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : Exception


    1. Hi SCCM_Admin / Leca, did you ever get to the bottom of this error ? I’m hitting the same issue & would like to avoid jumping through the same hoops ! Thanks, Dave.

  8. Hi Trevor, I’m using this background which works a treat, my only problem is that I’d like to identify the runspace(s) from another script so that I call kill them. I have continue on error enabled and a success and failure result group to action the necessary tasks depending on the result. The idea is in the failure group I would like to kill the runspace(s). Otherwise the fullscreen background is still present when the TS fails. A success is fine, because the upgrade has restarts which means i dont need to worry. Any ideas on how to achieve this?

    1. UPDATE: I’ve created a script that looks at all running processes, it filters the results that have the the name of the script (i.e. “Show-OSUpgradeBackground.ps1”) within the string found under the “CommandLine” and then gracefully terminates the process which will “close” the full screen blue background.

      Here is my script if it is of any use to anyone.

      $Processes = Get-WmiObject -Clasee Win32_Process -Filter “CommandLine like ‘%Show-OSUpgradeBackground.ps1%'”
      ForEach ($Process in $Processes) {
      $Result = ($Process.Terminate()).ReturnValue
      $ProcessID = $Process.Handle
      If ($Result -eq 0) {
      Write-Host “$ProcessID terminated successfully”
      } Else {
      Write-Host “Unable to terminate process”

  9. Hi, love the screen—-but I need to find a way to have it stop running after 30 seconds for example. How can I put a timer on this script? Thanks.

    1. Hi Steve,

      Have a look at my script above, you can use this as an action to perform in a do, while timer loop if need be.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.