In enterprise environments, we have to deal with a lot of requirements when it comes to app management. One of the common challenges is to control the installation moment during enrollment. We already have some basic controls in place. If the Enrollment Status Page (ESP) is configured during the enrollment all device targeted apps are installed in the “Device Setup” phase and all the user targeted apps are installed in the “Account Setup” phase. These are simple moments in time already. But what if you would like to schedule the installation after ESP when the Desktop is fully available and displayed?
The goal is to let a required Win32 app deployed via Intune install only if the ESP is not running anymore. Why? Maybe because we want to display a dialog for user interaction and this is only possible when the Desktop is fully loaded, otherwise the dialog will be hidden behind the ESP and can’t be interacted with. Resulting in an ESP waiting infinitely for an app which is hidden in the background :-(.
In fact, I needed this for my BitLocker PIN solution (How to enable Pre-Boot BitLocker startup PIN on Windows with Intune) already in the past but didn’t come up with a good idea how to solve it in a reliable way.
Now I gave it another try and solved it by doing the following.
The following approach worked well in my test environment, but not during the final implementation! The initial idea is used somewhere else where it is working successfully with a different precondition, but in the Autopilot requirement script, there is one caveat I found after releasing the blog. The following paragraphs still describe the way I approached the problem and finally also the issue discovered later with it. If you want to jump to the final solution, click here.
$(Get-Process -Name WWAHost).MainWindowHandle
If this gives us a value other than 0 the process is showing a Window currently.
The Requirement Script finally looks like this:
To demonstrate the whole story, here are a few screenshots of how this all works.
First, I checked if the theory actually works, so execution of the code in system context during the ESP “Account Setup” phase. We see the result of active:
I used my BitLocker PIN solution and then added the new requirement script to it and voila, it did what we expected from theory. The execution was prevented during ESP and first allowed after ESP wasn’t detected anymore (you can see the full Desktop in the background).
To get this result I simply added the Requirement Script to the BitLocker PIN solution like this:
Adding the Detect-ActiveESP.ps1 and do a string compare to ESP-not-active.
As l already demonstrated the BitLocker script was first shown when the full Desktop was loaded:
UPDATE 10/20/202 – changed approach:
The issue with this solution is that my test approach was altering the environment. By utilizing the [Shift] + [F10] hotkey to get a system command prompt I changed the preconditions! As soon as you enter the [Shift] + [F10] hotkey, the explorer.exe is loaded and this is a different precondition for my requirement script. I verified the script by utilizing this approach and it worked perfectly by executing the code in the command prompt. You may ask now: What is the issue? As soon as I started to use the code in the requirement script without the [Shift] + [F10] I was using during verification, it wasn’t working anymore. After digging deeper, I found this:
A process has a main window associated with it only if the process has a graphical interface. If the associated process does not have a main window, the MainWindowHandle value is zero. The value is also zero for processes that have been hidden, that is, processes that are not visible in the taskbar. This can be the case for processes that appear as icons in the notification area, at the far right of the taskbar.
This explains why my command prompt tests were successful as explorer.exe was loaded.
So, I gave it another try to find a different indicator when the desktop is loaded. It is not an elegant version (imho) and has some downsides, but it ist working for now. I simply take the “Windows Security notification icon” as an indicator for now. This icon is first started when the explorer fully loads in the User Desktop session:
The downside is, that the security icon should not be hidden by policy:
HKLM\SOFTWARE\Policies\Microsoft\Windows Defender Security Center\Systray\HideSystray = 1
As long as this precondition is given the solutions works fine for me.
You can find the updated simple Requirement Script on my GitHub:
I hope this solves a challenge that is coming up often. At least for me, it is useful and a real-world use case I have shown with the BitLocker PIN solution. I hope also it demonstrates how even your test approach may not always be sufficient. Feel free to leave a comment about what you have used it for or if you found a better solution!