When you are going through the OOBE process in Windows 11*, have you ever noticed that anything executing that displays a UI can’t be seen? A good example is the task sequence progress dialog that you would expect to see related to my previous post. You can tell that it is there by using Alt-Tab, but you can never get it to come to the front. Why is that?
The gory details are covered in a blog I stumbled across a couple of years ago. Effectively, Microsoft added a new capability into Windows that creates “bands” — app windows in lower bands can’t be above windows in the higher bands. This makes sense in some contexts, e.g. with floating toolbars, on-screen keyboards, and other UI elements that need to always be above other things. But this “Z-ordering” of windows into bands goes even further: there are some “bands” of windows that only appropriately-signed Microsoft code can use, along with undocumented APIs that enable you to use them.
This is exactly what OOBE is doing: putting itself in a protected Microsoft-only band where no other windows can be above it. So how do you get around this? Well, if you look at the ADeltaX blog, there is a way using DLL injection, but that’s basically a malware technique, not something you typically want to employ in a production environment.
So what other options are there? Well, there is a manual way. When you press Shift-F10 to open a command prompt, OOBE will move its windows into a “normal” band, which is what allows the command prompt and other apps launched from it to be visible. Once you do that, you can press Alt-Tab to get the task sequence progress UI to come to the front:
So then the question that arises is how to automate that. I want to run something that presses Shift-F10, closes the command prompt because it isn’t needed, and then brings the task sequence progress UI to the front. I initially tried a few different things (VBScript, PowerShell, etc.) before settling on a more powerful open source tool called AutoHotKey. This can hook into the OS in an appropriate way so that OOBE sees the Shift-F10 press and believes it is from a user at the keyboard. It provides a scripting language that enables us to do the other tasks as well. I ended up with this script:
So it sends Shift-F10 to the main OOBE window (titled “Microsoft account”), waits for the command prompt window to show up and then closes the process, and then brings the task sequence progress UI to the front, as long as it is already active. (You might have disabled it in the task sequence itself, so it’s not always there.)
The AutoHotKey tool also provides a utility that can convert the script into an executable, which is convenient: You can then add that as the first step of the task sequence itself. So that’s exactly what I tried:
I put the executable into a package, distributed that package, and added a step to the task sequence to run it. And guess what? It didn’t work. Why is that? From poking around, it appeared that I could only interact with processes within the same session (window station), a security feature that goes back to the early UAC days. So how do I get my executable to run in session 1, which is where OOBE is running? For that, I can turn to ServiceUI.exe that ships with MDT. It lets you create a process in any session. So after adding ServiceUI.exe to the package, I could modify the step’s command line:
So that’s “all” it takes — the right tools put together with an understanding of how the overall process works.
* Yes, this applies to Windows 10 as well, but I don’t use Windows 10 any more and neither should you. It’s time to move on.