UPDATE: May 2020 - UIPath have now released "Picture-in-Picture" mode as an experimental feature in UIPath 20.4 using the method detailed in this blog post. I expect that this will be picked up and integrated by other RPA vendors very soon.
---
If you have ever built or supported attended Robotic Process Automation (RPA) for desktop users, you know the biggest operational headache is the problem of the "hijacked mouse".
When an attended bot runs, it typically relies on UI automation to click buttons, fill forms, and scrape data. That means the user cannot touch their keyboard or mouse while the robot runs. If someone needs to run an automation that takes ten minutes, they either sit back and watch their screen flicker or walk away to grab coffee. If they try to check IMs or answer an email in the middle of the run, the focus shifts and the bot crashes. If you use tools such as Automation Anywhere, custom Python scripts, or legacy Windows programs that reject multiple concurrent instances (and/or require UI automation e.g. legacy ERP applications), you are stuck.
In enterprise settings, citizen developers face this constantly. Teams want the productivity gains of local task automation, but they do not have the budget or infrastructure approvals to spin up dedicated virtual machines for every worker (or want the administrative overhead). Virtual desktops solve the focus issue, but they add cloud compute bills, VPN overhead, and licensing costs.
To solve this on endpoints without deploying Hyper-V or third-party hypervisors, I built a two-part runner on top of an existing, overlooked Windows tool: the Windows Simulator.
What Is the Windows Simulator?
The Windows Simulator (Microsoft.Windows.Simulator.Client) was an .NET API originally designed by Microsoft for testing gestures and touch events in Metro applications for Windows 8. It was incorporated into the Visual Studio 2015 / 14.0 SDK. Since then, Microsoft subsequently expanded it for general software development testing and included it in subsequent versions of the Visual Studio SDK including the latest 2019 / 16.0.
Under the hood, the simulator does not emulate an entire machine like QEMU or VirtualBox. Instead, it spins up an isolated interactive Windows session on the local host using Windows Terminal Services (a child session), then projects that session into a window on your desktop.
Because the simulator uses native Windows session isolation: - It runs with near-zero external dependencies. - It does not require nested virtualisation, Hyper-V, or admin-heavy hypervisor installations. - The isolated session has its own input queue. A script can click and type inside the simulator window while you continue typing and clicking in your main workspace.
The challenge is orchestrating it. The raw SimulatorClient API gives you a hook to start an instance and launch a process, but it does not give you an end-to-end lifecycle manager. It does not monitor when the workload finishes, nor does it automatically shut down the session when the script completes.
Architecture
To make the simulator usable as a headless, unattended wrapper, I split the solution into two small .NET applications:
- Host Coordinator (
windows-simulator-net): Runs on the primary user desktop. It initialises the simulator session through the API, waits for the session to become healthy, launches the requested task inside it, and waits until the session terminates. - In-Session Process Monitor
windows-simulator-process-monitor-net: Injected directly into the simulator session. It executes the target workload, blocks until the workload process exits, and triggers an immediate session disconnect.
---------------------------------------------------------------------
| Host User Session |
| |
| [windows-simulator-net.exe] |
| | |
| | 1. Starts SimulatorClient |
| v |
| +-------------------------------------------------------------+ |
| | Windows Simulator Window (Child Terminal Services Session) | |
| | | |
| | 2. Launches windows-simulator-process-monitor-net.exe | |
| | | | |
| | | 3. Starts target workload (e.g. RPA bot, script) | |
| | v | |
| | [Target Application / Script] | |
| | | | |
| | | 4. Workload finishes | |
| | v | |
| | [Process Monitor calls tsdiscon.exe] | |
| | | | |
| | x Session disconnects and closes | |
| +-------------------------------------------------------------+ |
| | |
| | 5. Detects simulator process exit |
| v |
| [windows-simulator-net exits] |
---------------------------------------------------------------------
Driving the Simulator
The host coordinator references Microsoft.Windows.Simulator.Client.dll. Using SimulatorClient, we can start an instance asynchronously and track its initial state.
Once the simulator starts up, we need to inject the workload. We tell the simulator client to launch our monitor executable inside the session, passing the target executable and any relevant arguments:
StartProcessInfo startProcessInfo = new StartProcessInfo();
startProcessInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + "windows-simulator-process-monitor-net.exe";
startProcessInfo.Arguments = "\"C:\\Path\\To\\BotRunner.exe\" \"--task daily-sync\"";
// Allow a short delay for session services to settle, then start
await Task.Delay(TimeSpan.FromSeconds(delay));
simulatorClient.StartProcessAsync(startProcessInfo, processStartedCompRoutine);
After dispatching the process, windows-simulator-net polls the UI process ID of the simulator (GetUIProcessId()). As long as that window is open, the coordinator remains active. When the simulator window closes, the coordinator exits, providing a clean command line blocking mechanism that external orchestration tools or batch files can wait on.
Inside the Session and Safely Managing Exit
Once execution transfers into the child session, windows-simulator-process-monitor-net takes over. It launches the target process, waits for it to finish, and closes the session.
The key problem is how to exit cleanly. Closing the inner application does not automatically close the Windows Simulator instance on the parent desktop. If the user had to click the close button manually, the whole purpose of automated parallel execution would be defeated.
Because the simulator operates as a local Remote Desktop/Terminal Services session, we can invoke tsdiscon.exe (Terminal Services Disconnect)*.
Calling tsdiscon.exe logs off or disconnects the child session immediately. The simulator client recognises the session ended, shuts down its container window, and the host coordinator exits.
*(Hint: Pointing explicitly to C:\Windows\Sysnative\tsdiscon.exe bypasses file system redirection on 64-bit systems which can prevent it executing.)
Usage Example
Running an automation in an isolated session becomes a single line which can be executed from any source (PowerShell, .bat/cmd, shortcut, etc):
windows-simulator-net.exe "C:\Tools\RunBot.bat 'arg1 arg2'" 5
Here:
1. windows-simulator-net.exe launches the Windows Simulator.
2. It waits for the child session to stabilise.
3. It launches RunBot.bat inside the simulator via the monitor.
4. The user continues typing, browsing, and working in their standard Windows environment while RunBot.bat executes.
5. Once RunBot.bat completes, tsdiscon.exe fires, the simulator disappears, and the command finishes.
Constraints and Edge Cases
While this pattern works well on standard enterprise Windows images, child session isolation has several advantages and disadvantages:
1. Browser Profile Collisions
Some internet browsers restrict multiple sessions from reading and writing to the same user data directory concurrently. If your bot needs Chrome while the human is also using Chrome, you can use separate profiles by passing --user-data-dir="C:\bot-profile" to the browser instance in the simulator, or alternatively dedicate one browser to the bot and keep the other for personal browsing.
2. Windows PIN vs. Password Authentication
When connecting to a child terminal session, Windows uses the current user account. If the machine is set up with a Windows Hello PIN, starting the secondary session may prompt the user to input their domain password or PIN once. Using standard password login doesn't have an issue.
3. File Contention
Because both the host and the simulator share the local filesystem, the bot and the user must not write to the exact same file paths at the same time. It is best practice to use dedicated output directories or unique timestamped filenames.
4. Running Multi-Instance Locked Applications
Many older internal desktop applications enforce single-instance checks per session via local named mutexes. Running a second copy inside the simulator gives you an independent session, allowing you to open two copies of a stubborn single-instance application side by side.
Summary
You do not always need complex virtualisation stacks or costly dedicated VMs to unblock attended automation. By combining Microsoft.Windows.Simulator.Client with an in-session disconnect monitor, you can isolate GUI automations on standard Windows machines, keeping the user productive while the robot does its work.