Keeping an active desktop session

January 3, 2016

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.

Solution

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

High-level explanation:

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…”

image

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

clip_image002

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)

clip_image003

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 “cmd.exe

b. In the “Add arguments (optional):” textbox, type: “/c echo Hi >%userprofile%\desktop\output.txt

clip_image004

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:

clip_image005

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”)

clip_image006

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:

PowerShell %userprofile%\Desktop\ReturnDesktopSessionToConsole.ps1

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 <username> | 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 <username> 
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.

Known Limitations

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

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

24 comments

  1. tzurpSeptember 7, 2016 ב 10:49

    It’s working like a charm! Thak you!

    Reply
  2. DennisNovember 29, 2016 ב 12:56

    This information helps a lot… it might be the reason why this issue never happen on my local environment.

    Reply
  3. KasyapFebruary 6, 2017 ב 7:31

    This works! Only problem what I face now is with the display resolution. But screen resolution very low , so the tests are not able to access some of the UI controls.

    Can anyone help me to figure out how can I increase the screen resolution ?

    Reply
    1. Arnon AxelrodFebruary 23, 2017 ב 23:22

      @Kasyap – Have you tried using Set-ScreenResolution PowerShell command?

      Reply
      1. KasyapJune 14, 2017 ב 9:16

        @Arnon Axelrod : I tired the poweshell script you said to set the resolution and also tried with QRes.exe.
        Actually I am trying this in a VM. Will that be the issue?

        Reply
        1. Arnon AxelrodJune 26, 2017 ב 8:54

          That should work for VM too.
          If you’re using VMWare, then in vSphere the Console view is acting like the “physical screen”. There you can see what’s displayed on the main screen, and if you change the resolution there, you’ll see it there also.

          Reply
          1. KasyapJuly 25, 2017 ב 8:44

            Yes it works now ! Resolution in vSphere settings was the issue. Thanks a lot !

  4. sanjay bishtMarch 9, 2017 ב 7:04

    On running the powershell command it is showing the correct output but it is not creating the output file on the desktop

    Reply
  5. vsockAugust 6, 2017 ב 11:42

    I’ve been breaking my head for a week until I found this page. Many thanks the script has resolved the problems.

    Reply
  6. MarioOctober 11, 2017 ב 12:59

    No .txt file is written on the desktop.

    However, if I exclude -file from “–file %userprofile%\Desktop\ReturnDesktopSessionToConsole.ps1 >%userprofile%\desktop\output.txt”

    the .txt will appeat on the desktop. Is this approach fine?

    Reply
    1. Arnon AxelrodNovember 13, 2017 ב 12:15

      Did you look at the content of output.txt? I guess that you’ll see an error message there saying that ReturnDesktopSessionToConsole.ps1 is not recognized as the name of a cmdlet, function, script file, or operable program…
      In other words, I don’t see how this could work. See the PowerShell command line arguments.

      Reply
  7. Bruno JuchliOctober 12, 2017 ב 15:01

    You write that

    Usually Test Agents that are used for running UI automated tests are configured to log-in automatically and to interact with desktop.

    How can this be achieved? I already have auto-logon configured by Sysinternals Autologon utility, how about the “to interact with desktop” part?

    Reply
    1. Arnon AxelrodNovember 13, 2017 ב 10:56

      I’m not very familiar with Sysinternal Autologon, but I guess that auto login also implies “interact with desktop”…

      Reply
  8. kestasjOctober 18, 2017 ב 19:28

    Hi, for some reason my “DesktopOn.ps1” script was not executed from TaskScheduler. From PowerShell it looks OK I can see the TaskScheduler events which triggers the properTask, but “output.txt” was not created ?! k

    Reply
    1. Arnon AxelrodNovember 13, 2017 ב 10:51

      How do you know that the event was triggered? from the history tab? Did you try specifying a full path of output.txt?

      Reply
  9. kestasjOctober 18, 2017 ב 21:41

    Unfortunately it’s no working with Wnodws-VM, k

    Reply
  10. CleberOctober 27, 2017 ב 21:46

    Is there a way to keep multiple Windows accounts active at the same time?

    Reply
    1. Arnon AxelrodNovember 13, 2017 ב 10:01

      Hi Cleber,
      Can you explain what are you trying to do and why? What exactly do you mean by active Windows Accounts? Do you mean multiple active desktops, multiple logged in users, something else?
      All versions of Windows (except from “Home” AFAIR) support multiple logged-in users, but only one user can have an active desktop at any given time. Windows Server Remote Desktop Services allow multiple logged in users each to have an active desktop, but only one user can be auto logged in, therefore I don’t get what are you trying to achieve.
      Best,
      Arnon.

      Reply
  11. ShruthiNovember 10, 2017 ב 17:09

    Hi Arnon,

    This is a great article and solves my issue partially. We actually have a policy to display legal text upon login. Any idea how I can get around this so that the Test Agent can login and run the tests?

    Thanks

    Reply
    1. Arnon AxelrodNovember 13, 2017 ב 9:51

      Hi,
      If this text prevents the test agent from from logging in automatically, I suggest that you talk to your system administrator and explain the special need to remove this message just for that machine. I guess that they won’t immediately agree, but if you explain the need to your managers and convince them that it’s important I’m sure that a solution can be found.
      HTH,
      Arnon

      Reply
  12. warrenNovember 20, 2017 ב 7:23

    If you’re logging in as Administrator on each machine (not within domain network), it automatically stores user as *MachineName*/Administrator. I don’t see manual way to undo this.

    Attempting to import this to other machines fails since the MachineName part is always different. How can I make this generic “Administrator” so script is accepted on import into new machine?

    Reply
  13. Milan ZeleznikMarch 6, 2018 ב 13:35

    Everything done by your instructions, but screenshot (with powershell) still creates a black image…
    Any idea?

    Reply
  14. Nishant ShahMarch 28, 2018 ב 11:37

    Hi Arnon,
    The output file is not getting created for me as well when I try to execute it from Task Scheduler.
    However, when I try to execute the same thing via Command Prompt, everything works fine and get the output.txt file successfully with expected content.
    Any idea why is this happening ?

    Reply
    1. Nishant ShahMarch 28, 2018 ב 11:45

      Also, when I execute it from command prompt, I do get the session details correctly in the output.txt. But, above the session details, I get an error saying:-

      You cannot call a method on a null-valued expression.
      At ReturnDesktopSessionToConsole.ps1:3 char:1
      + $sessionId = $output.Substring(38, 9).Trim()
      + CategoryInfo : InvalidOperation: (:) [], RuntimeException
      + FullyQualifiedErrorId : InvokeMethodOnNull

      Reply