Deploying applications to server farms

This article addresses the problem that it is often necessary to deploy an identical array of applications to a set of servers in a farm, especially with Remote Desktop Services RemoteApp or Citrix server farms, where the same array of applications must be available on all servers.

The proposed solution on this page is in two parts. The first part installs a scheduled task on each server through group policies and the second part installs the software from a central script. With this approach, there is no need to change anything on each individual server, when a new application must be available.

Deploying applications to server farms

Nuts'n'bolts or point'n'click?

Let's rewind a bit and look at the overall picture, to get an understanding of best way to do it in your case.

There are generally two approaches to solving the software distribution problem. This page outlines the nuts'n'bolts approach, which is a little bit more work in return for more flexibility. With this approach, you go into the Script Editor and create a scheduled task MSI package and then write your own script to handle everything. This way you get the full might of the scripting language, which has about 1500 commands.

The other simpler way is to use the Software Deployment wizard, which is explained here. This approach is purely point'n'click and is usually the best way. This wizard is actually based entirely on the solution explained here, wrapped in a wizard that will write the actual install script that you would otherwise have to write yourself. But you are of course limited to what features, it can write scripts for. This is what the wizard looks like:

General Software Deployment

If you find the Software Deployment wizard to fulfill your needs, that is probably the best way to go. If you feel you need to do complex work, not only installing the software itself, the approach outlines here may be the better way to go. Read on for the first nuts'n'bolts approach.

Step 1: Deploying a bootstrapper script to all servers

The approach is to deploy a bootstrapper script once and for all through an MSI package via Group Policies to all servers in the farm and then handle all installations from one single central script. This approach is to avoid (re)deploying MSI packages each time there is a change in the set of applications to install.

The central script must to be called once a day from each server and the local bootstrapper script is solely a means to establish credentials and get the central installation script executed. The locally installed bootstrapper script could look like this:

ConnectShare X:,\\AcmeServer\citrixadm$,Acme\Install,Akut3sRS6e3kJHztyeqg9w==

SetCurrentDir X:\Installers

Include Controller.fsh

DisconnectShare X:

Each server is connecting the share \\AcmeServer\CitrixAdm$, where a script called Controller.fsh in located in the root "Installers" folder. This script would contain the actual logic to install applications that are not already installed (see step 2).

Central script

To deploy the bootstrapper script above to all the servers, the script must be compiled into an MSI package first to be distributable. When the above script is open, click the "Compile to Msi" button in the script editor or press F12.

Creating MSI file from project

When the MSI window is open, select "Compile script into a Scheduled Task inside an MSI package". This will insert two scheduled task pages after the initial welcome page. Note that the compilation supports randomization hours to spread the load. You can change this random interval on the second page of the wizard to install software during the night for example. Leave the credentials page by its defaults, as credentials are built into the script.

Scheduled task contained inside an MSI to install software

Compiling a script into a scheduled task inside an msi package is explained in more detail on the msi page. Note that each server will not require FastTrack Scripting Host (the run-time) to be installed, as the MSI package contains the run-time to execute the scripts.

Once the script is compiled into an MSI file, simply assign a software installation through a group policy to all your servers, as explained on the msi page.

Step 1: An alternative version

In the above example, the scheduled task is running under the system account and a network drive was mapped to include the controller script and get access to installation files. It is also possible to install the scheduled task as a domain admin and then simply use an UNC path:

Scheduled task contained inside an MSI package page 2

The bootstrapper script could then simply include the script, as the script is already running under a domain admin account:

Include \\AcmeServer\citrixadm$\Installers\Controller.fsh

Step 2: Installing the software

We now know that each server will call our "Controller.fsh" script once a day. To avoid relying on each servers installed programs list, we will use the RegisterInstallation command to register installations as described on the installations page.

The reason we are not using the Windows installation list listed in the control panel, is because it is hard to get exact and unambiguous information. Often the installation name contains a version number, a language flavor or similar, which means that the application name is not unique across future versions. Instead we keep our own list of applications, where we decided names and versions ourselves, by using RegisterInstallation and supporting conditions. The "Controller.fsh" script looks as shown below. You can insert the script directly in the script editor by selecting "Farm App Deployment" in the "New Script" window.


If Not Server Then Exit



LogEvent Controller,Central controller script started



InstallMSIPackage AcmeApp1.MSI,Acme App 1,6.0,1

InstallMSIPackage AcmeApp2.MSI,Acme App 2,1.0,1

InstallExe CustomSetup.Exe,/S,Custom Program 1,7.0,1





/* LOG END */

LogEvent Controller,Central controller script finished




Command InstallMSIPackage(MSIPath, Name, Version, Build)

  If Not InstalledBuild [Param Name],[Param build] Then

    Run MSIExec.exe,/I [Param MSIPath] /QN /NoRestart

    If [LastExitCode]=0 Or [LastExitCode]=3010 Then

      RegisterInstallation [Param Name],[Param Version],[Param Build]

      LogEvent Installation,[Param Name] installed.

    End If

  End If

End Command



Command InstallExe(ExeFile, ExeParams, Name, Version, Build)

  If Not InstalledBuild [Param Name],[Param build] Then

    Run [Param ExeFile],[Param ExeParams]

    If [LastExitCode]=0 Then

      RegisterInstallation [Param Name],[Param Version],[Param Build]

      LogEvent Installation,[Param Name] installed.

    End If

  End If

End Command

The script logs events to the local event viewer to make sure that we can trace what is actually going on in case of problems. In the example two MSI-based applications "Acme App 1" and "Acme App 2" are installed, if they are not already installed on each server and a non-MSI based application named "Custom Program 1" is also installed.

It is safe to call the script every day, as the "InstalledBuild" conditions will prohibit the installations from running more than once per server. As more applications must be installed, we can now just insert one new script line for each new package and it gets installed on each server at next triggering of the scheduled task.

Now that we are sure that we get a script executed on each server every day, we might as well do other things also. The script therefore uploads inventory to SkyBox, but it would also be easy to do a disk space check and send an email, if a server is low on disk space. The script could also be used to run SQL Server or other backups.

Test and verification

When later adding new applications or updating existing ones, we need to be able to test and verify the script changes. As the trigger task now exists on all servers, any one server can be used to test. Simply open the Task Scheduler on the selected test server, identify the trigger task and run it manually. Then run a number of iterations with script alteration and manual task start until the script works satisfactory.

The next morning we need to verify that all servers now have all the applications that are expected. As we are using SkyBox, we don't need to log onto each server and look at the Windows installed programs list to verify. We can log on to our cloud web account instead and look at the software list. The number of servers in the list that have each new or changed application should match the number of servers that has the trigger task, and if not, the software list will reveal the missing server(s).

Rating: 5 out of 5

"Use this as a replacement for VBScript and PowerShell"

"It's easy to include attractive GUI elements in FastTrack scripts, beyond the basic dialog boxes and text input that VBScript offers ... Another powerful feature is the ability to distribute scripts as Windows Installer (.msi) or standard .exe files. Although interesting in its own right, this ability results in a much more intriguing capability: to repackage -- or wrap -- software installers as .msi files without using snapshots. If you've ever created an .msi installer file from before-and-after system snapshots, for use with a software distribution system such as Group Policy or SCCM, then you know how hit-and-miss the results can be."

Read full review

Rating: 8 out of 10

"Faster than the rest"

"We found the FastTrack syntax to be more transparent and easier to learn than Microsoft's PowerShell – the editor in particular provided good support in this regard. the Script Editor offers a large number of options from the command set through to simple output of graphical elements, which cannot be achieved at all with PowerShell or other solutions or only with a significantly greater level of effort."

"Anyone wanting to tackle the many hurdles in everyday admin and especially anyone for whom logon scripts and client automation is a priority will benefit from the variety of functions offered by FastTrack."

Review in English      Review in German