Automating Windows tasks that require a desktop window
Sometimes it is necessary to perform automation on one or more Windows programs that require an actual Desktop Window to be created. Such applications are heavily end user oriented and not built for batch operation without a GUI.
Normally a process definition runs on Microsoft Windows as either the System
account, the default RunAs
account set via the DefaultRunAsUser process server parameter, or the process definition RunAs
attribute. Such jobs are able to create a GUI window, but all windows are created in such a way that all actions on it are disregarded. No Windows messages will ever arrive on its message loop thread. If you take a screenshot of the screen you will find that it is completely black.
There are three main reasons why you may want to have the application create a real window:
- An application may be technically restricted in that it does not work if its GUI windows are not completely populated or its message loop does not function.
- An application may not have automation capabilities that can be used to drive it to perform the desired action, and there is no other option than emulating a human operator by controlling it via its GUI.
- An application does not have a capability to log errors or progress via any other means than a GUI.
The platform agent can create a full-blown Windows Session. As there is a sizable overhead with creating such a session the intended usage pattern is that a session is created (a user is logged on via RDP) and then used in a number of related processes. Once all related processes are done the session is closed (the user is logged off via RDP.)
As such sessions use a lot of Windows resources, and Windows normally restricts each computer to one session per user, their use should be minimized.
To use the Windows Sessions support, create the following:
- A Queue that is served by only one process server with the platform agent service, running on Microsoft Windows 2012R2 or higher. This system must have enough RDP session licenses to serve the number of desired parallel sessions. Set the width of the queue to the number of RDP sessions you want to run in parallel.
- At least one Windows user for every parallel session. For instance, if you intend to have 2 parallel sessions you must have at least two users. These users must have RDP privilege on that system - test this by logging on to the system remotely using RDP as that account.
The tasks that are scheduled on that server will all use this queue. Do not use sessions in multiple queues on the same server, nor schedule sessions on that server using multiple instances of the product.
For every task that needs to run (which can consist of multiple process definitions) you create a chain that contains two special process definitions - one to create the session and one to close it. As creating a Windows session is a process that can be expensive in resources (it has been seen to take Windows more than 60s to log a user on) it is recommended to group tasks that can run in series or parallel together and group them in a Chain.
To run as part of the session the process definitions must have a Opaque session handle JCS_SESSION
parameter in their definition. The value for this parameter is not for use by the Process Definition itself but for the session manager in the platform-agent.
Built-in definitions
The following built-in process definitions allow you to open and close RDP sessions on a remote Windows system. Note that the System_Windows_Session_Close only closes the sessions opened by System_Windows_Session_Create it is linked to via the opaque session handle.
You use these process definitions in a chain and map the opaque session handle JCS_SESSION
parameter.
System_Windows_Session_Create
has an out parameter JCS_SESSION
, your own process definitions and System_Windows_Session_Close
must contain an in parameter JCS_SESSION
.
How it works
The System_Windows_Session_Create
definition is treated specially by the system because it has an out JCS_SESSION
parameter. Such a definition will try to allocate a Windows User Session using one of the accounts allowed by the JCS_SESSION_ACCOUNTS
parameter. The first account in that list that is not yet running a session according to its own administration will be used.
The JCS_SESSION_TIMEOUT
parameter can be set on the session creation definition to specify the maximum time that the session may last. If the session is active longer, it will be aborted by the system. The standard definition takes a Number parameter containing the maximum number of minutes, but a DateTimeZone may also be specified (by duplicating the Process Definition.)
The System_Windows_Session_Close
is treated as the last Process Definition in the Windows Session because it uses the special keyword {logoff}
in the RunAs attribute.
The RunAs field, in any of these definitions, is ignored other than the special {logoff}
flag. This is useful as it means you can specify credentials and other flags for use in other situations where it is not called in the context of a Windows Session.
If needed you can duplicate the Create and Close system definitions, and tune them for your own use.
Note that it is not required to use a Chain, any way in which the JCS_SESSION
parameter is passed on to later process definitions is permitted. It is also possible to run multiple process definitions in parallel in the same Windows Session by using a chain with multiple calls in a step. The only condition that the system makes is that you tell it when you are done with a session by running a Process Definition with the {logoff}
RunAs attribute. Also, if you do use a chain it is not necessary that every process in it runs on this particular Windows server; you can also run other processes in other servers if necessary.
You can use the jtool screenshot facility to monitor progress and any visual errors.
Example
Chain with Steps for Opening and Closing the Session
A basic chain using Windows Sessions support has the following layout:
Step 1
System_Windows_Session_Create
Step 2
MSLN_Screenshot
Step 3
System_Windows_Session_Close
In the chain editor, under Step 3 you choose the field of the Opaque session handle JCS_SESSION
parameter and
hover over the process in Step 1 and select the JCS_SESSION
from the parameter list. You add a new parameter
on the chain named Accounts
of type String array and map that with the JCS_SESSION_ACCOUNTS
of
System_Windows_Session_Create in Step 1. Then choose the JCS_SESSION
parameter of Step 2 and hover over the process in Step 1 and select the JCS_SESSION
from the parameter list.
The MSLN_Screenshot process definition is of type CMD, and the following Source field:
jtool screenshot
Ensure it has a String parameter named JCS_SESSION
with Direction In.
Result
Submitting the chain with Accounts
set to jdoe@example
creates an RDP session for user jdoe
( Step 1 ), takes a screenshot ( Step 2 ), and finally closes the RDP session ( Step 3 ).
Single process
- You duplicate
System_Windows_Session_Create
and give it a new name. - You specify
{logoff}
in the Run As User field; this ensures the user will be logged off once the code in the Source field has been run. - You optionally select the definition type you favor for your code; in this example, the code is Powershell (
PS1
) so the default is used creates a temporary file with some text, opens the text file with notepad.exe, takes a screenshot, and finally closes thenotepad.exe
window.
jtool echo 'Created session'
jtool screenshot
$tmpfile = [System.IO.Path]::GetTempFilename()
Set-Content -Value "Hello World" $tmpfile
$ntpd = start-process notepad $tmpfile -PassThru
Start-Sleep -m 500
jtool screenshot
$tmpout = $ntpd.CloseMainWindow()
$ntpd.Close()