UPDATE: For some reason, the solution as it was before didn’t always work. I don’t understand the root cause, but the solution was simply to remove the “-file” at the start of the arguments of the Task’s action. I now fixed the instructions below accordingly.
When doing any kind of UI automation, there are several cases that a desktop session will be active. I’ll get to what it actually means in a second, but first I want to list some of the common problems that people encounter that are caused by not having an active desktop session:
1. In Coded UI, you get the exception:
Microsoft.VisualStudio.TestTools.UITest.Extension.UITestException: Automation engine is unable to playback the test because it is not able to interact with the desktop. This could happen if the computer running the test is locked or its remote session window is minimized
2. Taking a screenshot in Internet Explorer using Selenium WebDriver creates a black image
3. AutoIT or InputSimulator doesn’t work on a remote machine
4. Taking a full screenshot (not through Selenium) creates a black image
These problems are often left as a mystery for those who encounter them. So here I am to shed some light on them and suggest a solution!
What’s an active desktop session?
Normally when you turn on a regular Windows machine, you must first Log-in before you can do anything useful. When you do, whatever you see on your screen is your active desktop.
If you then leave your computer for few minutes, your desktop would probably be locked and you’d have to enter your credentials again. Note however, that during that period of time you were still logged-in, even though you didn’t have an active desktop. After you unlock, every window that was opened before the computer was locked, is still open.
If you then go to another computer, and open a Remote Desktop connection to your first computer, the real monitor on that computer also shows the “locked” screen, but now you can see all your open windows through the remote desktop window. In this case, the Remote Desktop connection is your active desktop session
If you then close the Remote Desktop connection, even though you remain logged-in, the main monitor still shows the “locked” screen (at least in the recent versions of Window), and because no one is connected, you now don’t have an active desktop session. Of course that if you re-connect through Remote Desktop or unlock through the main monitor, you’ll still get your open windows.
But wait, it’s a VM! It doesn’t have a monitor…
The confusing thing here is that most often the machines that you’re using for running your automated tests in the build process (Test Agents), don’t actually have a monitor, or at least no one uses it on a regular basis. In most cases these machines are actually a Virtual Machine and sometimes you don’t even have access to the management console of the VM (e.g. vSphere in case of VMWare). However, every machine (physical or virtual) has a primary monitor, even if it’s not connected or you don’t look at it in the VM’s management console.
So how do I get to this state?
Usually Test Agents that are used for running UI automated tests are configured to log-in automatically and to interact with desktop. This means that after the machine (or VM) is started, it has an active desktop (on its main monitor) and everything is fine.
Then, when you want to access this machine for any reason, you open a Remote Desktop connection to it. In this case you still have an active desktop (even though it’s a new one, instead of the original one)
However, when you then disconnect your Remote Desktop connection, you’ve actually closed the active desktop and the processes that need to interact with desktop can’t do that… If you are able to look at the main monitor (or the VM’s console), you’d still see the “Locked” screen. This is when the problems mentioned above occur.
While searching for a solution to that problem, I discovered many little interesting things that I didn’t know before. One of them is that Windows Task Scheduler can trigger tasks not only based on timings, but it can also trigger tasks based on events! One of these events is that a remote desktop session has disconnected! (In fact, Task Scheduler allows you to register to any event that may be written to the Event Viewer!)
In brief, the solution is composed of few pieces
1. A Task Scheduler’s task that is triggered upon disconnecting form Remote Desktop
2. The query session command
3. The TSCon command
4. A PowerShell script that combines the 2 commands
The scheduled task triggers the PowerShell script upon disconnecting from Remote Desktop. The script invokes the “query session” command to find the identifier of the relevant session, and then uses that identifier as an argument to the “TSCon” command which transfers the session to the console (i.e. main monitor)
And here are the details:
Creating the Scheduled Task
First, Login using Remote Desktop to the machine that runs the Test Agent. I assume that you normally do so using the same credentials of the Test Agent process (otherwise you won’t see what the automated tests is doing…)
Here we’re going to create the appropriate scheduled task that will be triggered when you disconnect from Remote Desktop. In the first stage, we’ll just write “Hi” to a text file just to see that it works. Later we’ll change it to run a PowerShell script that we’ll write later, that will return the desktop session to the “Console”.
1. From the Start menu, open Task Scheduler
2. Right click on the root (“Task Scheduler (Local)”) of the tree on the left pane, and select “Create Task…”
3. In the General tab of the Create Task dialog:
a. Type the name for the task. E.g: “ReturnDesktopSessionToConsole”
b. Select the “Run whether the user is logged on or not” radio button
c. Check the “Run with highest privileges” checkbox
4. In the “Triggers” tab, click “New…”. In the “New Tigger” dialog:
a. In the “Begin the task:” drop down list, select “On disconnect from user session”)
b. Select the “Specific user:” radio button (the user name that you’re currently logged-in with should appear. This should also be the same user that runs the Test Agent)
c. Click OK to close the dialog
5. Move to the “Actions” tab and click “New…”. In the “Edit Action” dialog:
a. In the “Program/script” textbox type “
b. In the “Add arguments (optional):” textbox, type: “
/c echo Hi >%userprofile%\desktop\output.txt”
c. Click “OK” to close the dialog
Note: this is a temporary task that just creates a file called “output.txt” on the desktop with the content “Hi”. Later we’ll replace this with something more meaningful, but let’s first check that we’ve done it right.
6. Click “OK” to close the “Create Task” dialog. Enter your credentials if you’ve been asked.
Let’s check what we’ve done until now:
Let’s first check that the Action was defined correctly:
Expand the “Task Scheduler (Local)” node in the tree and select its child “Task Scheduler Library”.
At the upper pane of the window you should see a list of existing tasks (possibly only with the task you’ve just created). Find the “ReturnDesktopSessionToConsole” task, right click on it, and select “Run”, as shown in the following screenshot:
Go to the desktop and check if the file “output.txt” exists. Open it and ensure that it contains the word “Hi”.
Delete this file for further checks!
If something went wrong, you should enable Task History and try again:
In the “Actions” pane on the right, if there’s an item labeled “Enable All Tasks History” – click it. (After doing so it will be replaced with “Disable All Tasks History”)
After running the task again, you should see some events in the “History” tab at the bottom of the window (when the relevant task is selected). Look at this events to see what the problem was.
Note: you may need to press F5 to refresh the “status” of the task and/or the history.
Now, let’s check that the trigger is correct:
Make sure to delete the “output.txt” file from the desktop, and then close your Remote Desktop connection. Then connect again.
Look for the “output.txt” and see that it was created again. If it hasn’t, look at the Task history to identify the problem.
Creating the PowerShell script
Now let’s replace the action that just writes “Hi” with what we really need
1. Make sure that PowerShell execution policy allows you to run PowerShell scripts:
a. Create a new empty file called “test.ps1” on the desktop (you can use Notepad for that)
b. Open an elevated command prompt window (Run as Administrator), and type:
If nothing happens, it means that you can run PS scripts. In this case, just to the next step.
However, if you get a red error message stating that the file “cannot be loaded because running scripts is disabled on this system.” You should run the following command:
PowerShell –command set-executionpolicy remotesigned
2. Open “ReturnDesktopSessionToConsole.ps1” in notepad, and copy the following script:
$output = query session &amp;lt;username&amp;gt; | findstr /I “ Disc “ # The session id starts at the 38th character and is maximum 9 characters long $sessionId = $output.Substring(38, 9).Trim() Tscon $sessionId /dest:console #write the date and the current sessions so we can see the output when it ran and that it completed successfully date query session &amp;lt;username&amp;gt; echo OK
Replace the 2 occurances of <username> with the actual username that you’re using on that machine. Save the file and close Notepad.
Now, edit the scheduled task to run the new script instead of just writing “Hi”:
1. Expand the “Task Scheduler (Local)” node in the tree and select its child “Task Scheduler Library”.
2. At the upper pane of the window, find the “ReturnDesktopSessionToConsole” task, and right click on it to open its context menu
3. Click “Properties”
4. In the “ReturnDesktopSessionToConsole Properties (Local Computer)” dialog, select the “Action” tab
5. Click “Edit…”
6. Replace the value in the “Program/script:” text box to “PowerShell” (instead of “cmd.exe”)
7. Replace the value in the “Add arguments (optional):” text box to “
%userprofile%\Desktop\ReturnDesktopSessionToConsole.ps1 >%userprofile%\desktop\output.txt” (note that the last part, after the “>” remains the same as it was, because we want to redirect the output of the command to the output.txt file on the desktop, so that we’ll be able to investigate it if something went wrong).
Note: if this doesn’t work for you, try to add “-file ” or “-command ” at the beginning of the arguments string.
8. Click “OK” to close the “Edit Action” dialog
9. Click “OK” again to close the Task Properties dialog. Enter the credentials when asked.
Copy the solution to multiple machines
If you need to apply that solution to multiple machines, here’s a small tip that can help you:
Given that you’re using the same user for all the machines, and you use the same paths, you can export the scheduled task that you created (right-click on the task and select “Export…”). This will create an XML file that contains all the details of the task. Then you can copy that file together with ReturnDesktopSessionToConsole.ps1, to the other machine, and import the task file to the Task Scheduler (right click on the “Task Scheduler Library” node in the navigation tree, and select “Import Task…”.
That’s it! You should now try it!
In case something didn’t work as expected, examine the “output.txt” file on the desktop, and/or the task history.
Note that in case of success, “output.txt” should contain the date and time when the script ran, the active sessions of <user>, and “OK” as the last line.
1. This “trick” doesn’t solve the problem if someone minimizes the Remote Desktop window. Make sure that you either leave the Remote Desktop window open (even if it’s in the background) or closing it completely.
2. I didn’t tried it in all cloud providers, but on Azure I found that taking a screenshot or recording a video when there’s no Remote Desktop connection open, shows the screen as it was when the last Remote Desktop connected has been closed. (Even the clock in the Tray displays that time!!)
Please let me know if it helped you or not, so I can improve this post as necessary!
Thanks! See you next time J