Chat now with support
Chat with Support

Welcome, erwin customers to Quest Support Portal click here for for frequently asked questions regarding servicing your supported assets.

Enterprise Reporter 3.2.1 - ToolBox User Guide

Executing Tasks Using Chain Files

The tool provides a number of tasks which can be chained together using what is called a “chain file”; each task in the chain file will be executed, one at a time, in sequence from top to bottom. A chain file is simply an XML file with the following format:

 

<?xml version="1.0" encoding="utf-8" ?>

<TaskChain [failonerror]>

<task name="Task1" [enabled] [id] [fatal] [showalloutput]>

<args>

<arg name="X”>X-value</arg>

</args>

</task>

...

<task name="TaskN" [enabled] [id] [fatal] [showalloutput]>

<args>

<arg name="X”>X-value</arg>

</args>

</task>

</TaskChain>

 

The documentation for each task provides a complete and legal chain file as part of its output. This allows the tool to be self-documenting. Simply copy the complete block of XML from any task into a new text file and then add the appropriate <task> blocks for any other tasks you wish to execute. Once that is done, replace the arguments with your own values and the chain file is ready for use.

A new execution mode has recently been added. We call this debug mode and it executes a chain file in exactly the same way as the standard Execute Mode but it dumps the contents of all variables (declared, injected and task-local) prior to executing each task. This can be useful for tracking down errors.

There are two ways that the ToolBox will locate chain files:

Note that this is the order in which the tool will search. If there is a file named, “chainfile.xml” in both the current working directory AND in the directory referenced in TOOLBOX_SCRIPTS, then it will be the script in the WORKING DIRECTORY that will be executed. In the event a file cannot be located, then ToolBox will make a best-guess based on a Levenshtein Distance calculation for all files in the current working directory and the TOOLBOX_SCRIPTS directory.

Follow is a real example of a chain-file.. The actual file contains many more files, but this stripped-down version is sufficient to explain all the details of a chain file.

 

<!--This file is named ‘SampleValidateProjectDetails.xml’ -->

<?xml version="1.0" encoding="utf-8" ?>

<TaskChain>

<vars>

<var name="!(serverpath)">C:\Program Files\Quest\Enterprise Reporter\Server</var>

<var name="!(configpath)">C:\Program Files\Quest\Enterprise Reporter\ConfigurationManager</var>

<var name="!(reportpath)">C:\Program Files\Quest\Enterprise Reporter\ReportManager</var>

<var name="!(asmversion)">3.1.0.0</var>

<var name="!(fileversion)">3.1.0.1736</var>

</vars>

 

<!-- Server -->

<task name="ValidateProjectDetailsTask" id="server" fatal="false" enabled="false">

<args>

<arg name="AssemblyVersion">!(asmversion)</arg>

<arg name="FileVersion">!(fileversion)</arg>

<arg name="CompanyName">Quest</arg>

<arg name="Files">

!(serverpath)\Category.dll,

!(serverpath)\DatabaseWizard.exe,

!(serverpath)\DBConsole.exe,

!(serverpath)\DbLibrary.dll

</arg>

</args>

</task>

 

<!-- Configuration Manager -->

<task name="ValidateProjectDetailsTask" id="configuration manager" fatal="false">

<args>

<arg name="AssemblyVersion">!(asmversion)</arg>

<arg name="FileVersion">!(fileversion)</arg>

<arg name="CompanyName">Quest</arg>

<arg name="Files">

!(configpath)\CollectorUI\Quest.Reporter.Consoles.Discovery.
CollectorViews.dll,

!(configpath)\ConfigurationManager.exe,

!(configpath)\Quest.Common.AMConnector.dll,

!(configpath)\Quest.Reporter.Configuration.PowerShell.dll

</arg>

</args>

</task>

 

<!-- Report Manager -->

<task name="ValidateProjectDetailsTask" id="report manager" fatal="false">

<args>

<arg name="AssemblyVersion">!(asmversion)</arg>

<arg name="FileVersion">!(fileversion)</arg>

<arg name="CompanyName">Quest</arg>

<arg name="Files">

!(reportpath)\Category.dll,

!(reportpath)\Quest.Common.AccessManagerHelper.dll,

!(reportpath)\Quest.Common.AMConnector.dll,

!(reportpath)\Quest.Common.SqlParsing.dll

</arg>

</args>

</task>

</TaskChain>

 

XML Comments

The chain file may contain XML comments. A chain-file is simply an XML file, so anything that is valid inside an XML file is valid in a chain file.

 

Task ID

Each task has an “id” attribute. This makes it possible to distinguish the exact usage of a task within a chain file. Looking at the example above, the chain file has used the same “ValidateProjectDetailsTask” three times. If an error were to occur, it would show that it had occurred in a task of type “ValidateProjectDetailsTask” but it might be difficult to identify exactly which call was causing the error. It is possible to narrow down an error to the specific usage of a task using the unique identifier on each of the tasks. The ID, “env” is reserved for the system to use when importing system environment variables.

Enabled

BOOLEAN - By default, ToolBox will run all tasks found within a chain-file. Sometimes, it is convenient to be able to prevent a task from running. In such cases, it is not necessary to resort to removing the task or commenting it out as the enabled attribute can be used to keep a specific task or hierarchy of tasks (see Advanced Topics) from running.

 

Show All Output

BOOLEAN - By default, ToolBox displays only error messages. By specifying a value of true for this attribute, all output will be displayed (both success and errors).

 

Fatal

BOOLEAN - This attribute determines whether or not the task should terminate the run; the default is to terminate the run whenever a task encounters an error. This behavior can be over-ridden by marking non-essential tasks as non-fatal.

 

Passing Multiple Arguments

Each “Files” argument contains multiple filenames separated by commas. Standard rules for parsing CSV files apply. A future enhancement will allow multi-value arguments to separate items within an <item></item> tag.

Variables

Variable names are case-insensitive and come in four different flavours:

Declared variables are placed into a <vars></vars> block at the head of a chain file.

 

<?xml version="1.0" encoding="utf-8" ?>

<TaskChain>

<vars>

<var name="!(questroot)">C:\Program Files\Quest\Enterprise Reporter<var>

<var name="!(serverpath)">!(questroot)\Server</var>

<var name="!(configpath)">!(questroot)\ConfigurationManager</var>

<var name="!(reportpath)">!(questroot)\ReportManager</var>

<var file="c:\globalvariables.xml"/>

</vars>

</TaskChain>

 

Chain files may contain variables in a <vars> section at the head of the file. This allows using these variables within the chain file to avoid typing repetitive text. In the example above, they have been used to represent directories off a common root path. Using this approach not only makes it easy to replace a common root path but makes the script file easier to read and reduces the likelihood of introducing errors by missing paths in need of replacement.

 

Declared variables may make use of system environment variables by specifying a value in the form of a variable with the “env.” prefix. In the example below, !(windows) will be set to the value of the environment variable, “WINDIR”.

 

 

Variables defined in other chain files can also be included.

 

 

Declared variables are GLOBAL and visible to ALL tasks in a chain file.

Variables in a chain file may be injected from outside simply by specifying the replacement value on the command-line. For example, in the chain file shown above, the variable !(questroot) is defined as C:\Program Files\Quest\Enterprise Reporter.

If a new value is passed to this file during execution, using a command-line such as that shown below, the value in the file will be over-written in favor of the new value.

In this case, !(questroot) would be redefined as D:\Quest and the other variables would be updated accordingly.

One of the primary cases for using injected variables is when using the ToolBox in conjunction with TFS build. TFS defines various variables that can vary from one build machine to the next. By injecting variables the exact same chain file can be re-used and simply over-write those variables that need to be changed.

Injected variables are GLOBAL and visible to ALL tasks in a chain file.

When defining a task, values for the arguments associated with that task often must be provided. Arguments are, themselves, a form of variable. The primary difference (and the reason we distinguish between task arguments and variables) is that arguments to tasks are visible ONLY to the specific task (and instance of that task) that declares them and for which values are provided. Variables may be used in conjunction with task arguments as in the example below:

 

<?xml version="1.0" encoding="utf-8" ?>

<TaskChain>

<vars>

<var name="!(message)">This is a test message</var>

</vars>

 

<task name="Echo" id="msg">

<args>

<arg name="Message">The message variable contains: !(message)</arg>

</args>

</task>

</TaskChain>

 

The output of this task is:

 

TOOLBOX 3.1.0.1736

Identity: HALILITTLEWOOD\Ian

Host: HALILITTLEWOOD

Name: HALILITTLEWOOD

Exe: c:\Projects\Toolbox\bin\ToolBox.exe

Script: c:\Projects\testecho.xml

Arguments: -execute c:\Projects\testecho.xml

--------------------------------------------------------------------------------

START [Echo (msg)]

The message variable contains: This is a test message

END [Echo (msg)] OK 00m 00s 006ms

--------------------------------------------------------------------------------

SUMMARY

Date: May 10, 2018

Duration: 00m 00s 006ms

[Echo (msg)] OK 01:39:12.197 - 01:39:12.204 (00m 00s 006ms)

 

SUCCESSFUL RUN

Output variables allow a task to produce named variables that can be consumed by other tasks.

 

<?xml version="1.0" encoding="utf-8" ?>

<TaskChain>

<task name="Echo" id="msg01">

<args>

<arg name="Message">This is a test message</arg>

</args>

<outargs>

<outarg name="MessageLength" description="The length of the message"/>

</outargs>

</task>

 

<task name="Echo" id="msg02">

<args>

<arg name="Message">Message msg01 is !(msg01.MessageLength) characters long</arg>

</args>

<outargs>

<outarg name="MessageLength" description="The length of the message"/>

</outargs>

</task>

 

<task name="Echo" id="msg03">

<args>

<arg name="Message">Message msg02 is !(msg02.MessageLength) characters long</arg>

</args>

</task>

</TaskChain>

 

This chain file produces the following output:

 

TOOLBOX 3.1.0.1736

Identity: HALILITTLEWOOD\Ian

Host: HALILITTLEWOOD

Name: HALILITTLEWOOD

Exe: c:\Projects\Toolbox\bin\ToolBox.exe

Script: c:\Projects\testecho.xml

Arguments: -execute c:\Projects\testecho.xml

--------------------------------------------------------------------------------

START [Echo (msg01)]

This is a test message

END [Echo (msg01)] OK 00m 00s 007ms

--------------------------------------------------------------------------------

START [Echo (msg02)]

Message msg01 is 22 characters long

END [Echo (msg02)] OK 00m 00s 000ms

--------------------------------------------------------------------------------

START [Echo (msg03)]

Message msg02 is 35 characters long

END [Echo (msg03)] OK 00m 00s 001ms

--------------------------------------------------------------------------------

SUMMARY

Date: May 03, 2017

Duration: 00m 00s 020ms

[Echo (msg01)] OK 01:42:34.053 - 01:42:34.060 (00m 00s 007ms)

[Echo (msg02)] OK 01:42:34.066 - 01:42:34.066 (00m 00s 000ms)

[Echo (msg03)] OK 01:42:34.072 - 01:42:34.073 (00m 00s 001ms)

 

SUCCESSFUL RUN

 

These tasks contain an <outargs> block. This is optional in the chain file but should generally be left in place purely for documentation purposes. The output variable will be produced even if the <outargs> block is not included.

Each task also has the optional id attribute specified. This is required so that each output variable can be uniquely annotated. Consider what would happen if the attribute were omitted; the task with ID “msg01” would produce an output variable named “!(MessageLength)” but the next task would execute and over-write the variable with a new value. This can be avoided by prefixing the id of the task that produces the output variable so that the values can be preserved. This means that a task with id=”msg01” will produce a variable named, “!(msg01.MessageLength)”

Output variables are GLOBAL and visible to ALL tasks in a chain file.

Following is a very simple example of a chain file. This chain file waits for 1 second, then 5 seconds, then 10 seconds:

 

<?xml version="1.0" encoding="utf-8" ?>

<TaskChain>

<task name="Sleep" id="1s">

<args>

<arg name="TimeInSeconds">1</arg>

</args>

</task>

<task name="Sleep" id="5s">

<args>

<arg name="TimeInSeconds">5</arg>

</args>

</task>

<task name="Sleep" id="10s">

<args>

<arg name="TimeInSeconds">10</arg>

</args>

</task>

</TaskChain>

 

The output for this chain file looks like this:

 

TOOLBOX 3.1.0.1736

Identity: HALILITTLEWOOD\Ian

Host: HALILITTLEWOOD

Name: HALILITTLEWOOD

Exe: c:\Projects\Toolbox\bin\ToolBox.exe

Script: c:\Projects\testsleep.xml

Arguments: -execute c:\Projects\testsleep.xml

--------------------------------------------------------------------------------

START [Sleep (1s)]

Sleeping for 1 seconds

END [Sleep (1s)] OK 00m 01s 008ms

--------------------------------------------------------------------------------

START [Sleep (5s)]

Sleeping for 5 seconds

END [Sleep (5s)] OK 00m 05s 001ms

--------------------------------------------------------------------------------

START [Sleep (10s)]

Sleeping for 10 seconds

END [Sleep (10s)] OK 00m 10s 002ms

--------------------------------------------------------------------------------

SUMMARY

Date: May 03, 2017

Duration: 00m 16s 022ms

[Sleep (1s)] OK 01:47:23.633 - 01:47:24.642 (00m 01s 008ms)

[Sleep (5s)] OK 01:47:24.648 - 01:47:29.649 (00m 05s 001ms)

[Sleep (10s)] OK 01:47:29.653 - 01:47:39.656 (00m 10s 002ms)

 

SUCCESSFUL RUN

 

In the output, the first thing is the name of the chain file that was executed (“sleepychain.xml”).

Next, there are three START/END blocks showing that a task has started (START), which task has started (Sleep) and the identifier of that task (1s). If the task produced any output, it would appear between the START and END blocks. Finally, an END block shows the associated task (Sleep), the status of the task on completion (SUCCESS) and the total run-time of the task.

Finally, there is a summary of the entire chain file.

Advanced Topics

One ToolBox features provides the ability to wrap a set of one or more tasks in <parallel>…</parallel> to run the tasks in the set in parallel. Parallel has a single attribute, “threads” which accepts an integer detailing the maximum number of threads that should be running concurrently when executing the task. The default behavior is to immediately spawn each task in its own thread.

The ToolBox also provides the ability to wrap a set of tasks in <sequential>…</sequential>. At first glance, this may seem to be redundant; after-all, a Task-Chain is, by definition, a set of tasks to be executed sequentially. However, <sequential/> forces certain tasks within a <parallel/> block to execute in sequence while other tasks in the same block process entirely in parallel.

This first example is a traditional chain-file. Each task will execute in sequence. Total run-time will be approximately 30 seconds.

 

<?xml version="1.0" encoding="utf-8" ?>

<TaskChain>

<task name="Echo" id="Start">

<args>

<arg name="Message">Start</arg>

</args>

</task>

 

<task name="Sleep" id="A">

<args>

<arg name="TimeInSeconds">10</arg>

</args>

</task>

 

<task name="Sleep" id="B">

<args>

<arg name="TimeInSeconds">10</arg>

</args>

</task>

 

<task name="Sleep" id="C">

<args>

<arg name="TimeInSeconds">10</arg>

</args>

</task>

 

<task name="Echo" id="Stop">

<args>

<arg name="Message">Start</arg>

</args>

</task>

</TaskChain>

 

Graphically, this execution looks like so, where time runs down the vertical:

 

Start

A

B

C

Stop

This slightly re-written example will cause all tasks to be executed in parallel. Total run-time will be approximately 10 seconds.

 

<?xml version="1.0" encoding="utf-8" ?>

<TaskChain>

<task name="Echo" id="Start">

<args>

<arg name="Message">Start</arg>

</args>

</task>

 

<parallel>

<task name="Sleep" id="A">

<args>

<arg name="TimeInSeconds">10</arg>

</args>

</task>

 

<task name="Sleep" id="B">

<args>

<arg name="TimeInSeconds">10</arg>

</args>

</task>

 

<task name="Sleep" id="C">

<args>

<arg name="TimeInSeconds">10</arg>

</args>

</task>

</parallel>

 

<task name="Echo" id="Stop">

<args>

<arg name="Message">Stop</arg>

</args>

</task>

</TaskChain>

 

Graphically, this looks like so, where time runs down the vertical:

 

 

 

 

Start

A

B

C

Stop

This example shows how sequential blocks can be useful:

 

<?xml version="1.0" encoding="utf-8" ?>

<TaskChain>

<task name="Echo" id="Start">

<args>

<arg name="Message">Start</arg>

</args>

</task>

 

<parallel>

<task name="Sleep" id="A">

<args>

<arg name="TimeInSeconds">10</arg>

</args>

</task>

 

<task name="Sleep" id="B">

<args>

<arg name="TimeInSeconds">10</arg>

</args>

</task>

 

<sequential>

<task name="Sleep" id="C">

<args>

<arg name="TimeInSeconds">2</arg>

</args>

</task>

 

<task name="Sleep" id="D">

<args>

<arg name="TimeInSeconds">2</arg>

</args>

</task>

 

<task name="Sleep" id="E">

<args>

<arg name="TimeInSeconds">2</arg>

</args>

</task>

</sequential>

</parallel>

 

<task name="Echo" id="Stop">

<args>

<arg name="Message">Stop</arg>

</args>

</task>

</TaskChain>

 

Graphically, this looks like so, where time runs down the vertical:

 

 

 

 

Start

A

B

C
D
E

Stop

How is this useful? Well, one of the build tasks is used to build the Enterprise Reporter codebase. Some solutions are dependent on others, but others are independent. For example, each of the collectors takes approximately 1 minute to build. The collectors have dependencies on some solutions and other solutions have dependencies on the collectors, but the collectors have no dependencies on each other, so they can be built in parallel.

Related Documents

The document was helpful.

Select Rating

I easily found the information I needed.

Select Rating