Custom commands and functions

A custom command or function is basically a script block wrapped as a separate command or function, making it look exactly like any native command or function to the script constructor.

Some of the pros of structuring scripts this way, would be to encapsulate the complexity of script blocks and thereby make scripts easier to create and maintain. Another pro is ensuring reuse, to make sure any one operation executes the same way from any script.

Custom commands and functions can also be used as building blocks to split workloads. An external consultant could have made custom commands and functions for a customer, to use as building blocks to make scripter easier to construct and maintain. Or the custom commands and functions could have been downloaded from the internet - or it could simply be that one administrator has deeper technical knowledge that other internal script constructors and makes custom commands and functions for others to use.

Custom commands and functions

Custom commands

Let's create two custom commands. One to delete all files in a directory tree older than a specific number of days and the other to backup all sql server databases. These commands could be used to backup sql server files and then subsequently delete obsolete backup files. Our two custom commands look like this:

''Deletes all files older than a specific number of days from a directory tree

Command MyDeleteFilesOlderThan(Path,Days)

  Loop File,[SubFileTree [Param Path]]

    If [FileCreationDate [Var File]]<[SubtractDays [Param Days]] Then

      DeleteFile [Var File]

    End If

  End Loop

End Command


''Backs up all SQL server database files

Command MySqlBackup(InstanceName,Destination)

  StopService [Param InstanceName]

  SyncDir [ProgramFilesDir]\Microsoft SQL Server\MSSQL10.SQLEXPRESS\MSSQL\DATA,[Param Destination]

  StartService [Param InstanceName]

End Command

A custom command is a script block between a "Command" and "End Command" statement. We have decided to call our two commands "MyDeleteFilesOlderThan" and "MySqlBackup", both of which take two parameters. If a command takes no parameters, an empty set of parenthesis must be used. Inside the command, the "Param" function can be used to extract the parameter values for the command.

In the screenshot below, the above script lines were typed in to a new script. While keying in letters, something interesting happens. The script editor will at all times automatically sense when custom commands and functions are typed in or changed. The two custom commands we just typed in, are now showed along with all other commands and functions in the engine browser tree. All custom commands and functions will be shown under a root item called "Custom Commands and Functions".

Custom commands with FastTrack Automation Studio example 1 `
So now our two commands behave just like any other command, so if "M" is typed, our two new commands will show up in the command completion window:

Custom commands with FastTrack Automation Studio example 2 `
The command script blocks can be placed anywhere in a script or in included files. When using our new commands, our script lines calling them can be before or after the command blocks.

So putting our two new commands to work could look like this:

Custom commands with FastTrack Automation Studio example 3 `

Observe how the context helper now showed a useful help to using our "MyDeleteFilesOlderThan" command. Where did that come from? Let's look at the script again:

''Deletes all files older than a specific number of days from a directory tree

Command MyDeleteFilesOlderThan(Path,Days)

  Loop File,[SubFileTree [Param Path]]

    If [FileCreationDate [Var File]]<[SubtractDays [Param Days]] Then

      DeleteFile [Var File]

    End If

  End Loop

End Command

At the location of starting command or function block, the script editor looks at the previous line. If this line is a comment, this comment is used in the context helper in relation to this custom command or function. A comment block starting with /* and ending with */ can be also used to create multi-line help.

Custom functions

Custom functions are defined much the same way custom commands are, using a "Function" and "End Function" block instead. The main difference is that a function has to return a value. This is done with the "Return" command. A custom command can also use the "Return" command without parameters, in case it has to exit prematurely. The return value a function is not limited to one value; a list of values can also be returned, effectively making it a custom collection.

Let's try a scenario with a custom function. In a logon script, I would like to collect system information from clients, including screen information. Investigating "Screen" in the engine browser, reveals that I can get information about screen resolution, but I would also like to know if some users are still using legacy non-wide screen displays. This could of course be determined by collecting heights and widths, but it would be easier to just implement my own "ScreenRatio" function that I consider missing. So let's try that:

''Returns the ratio of the screen width and height

Function ScreenRatio()

  Return [Round [Calc [ScreenWidth]/[ScreenHeight]],2]

End Function


WriteXMLValue \\AcmeServer\Log$\Screens.xml,/ScreenRatios/[ComputerName],[ScreenRatio]

The engine already provides the functions to get height, width and the required math functions. So we simply divide the width and height, format that nicely with two decimals and return the result. We then use WriteXMLValue to log values from the logon script, using an XML file to make sure that we only keep one value per client, as values per computer are overridden in subsequent logons. With three example computers, the XML could look like this, revealing that PC8 is indeed using a legacy 4:3 screen:
As a footnote, observe that your custom functions and commands are slightly differently colored in the syntax highlighting. This way you do not need to investigate further, to determine if it is a custom function or not.


Our last example was implemented as a custom function. The same result could have been produced with a single script line:

WriteXMLValue \\AcmeServer\Log$\Screens.xml,/ScreenRatios/[ComputerName],[Round [Calc [ScreenWidth]/[ScreenHeight]],2]

This is much shorter, so why bother to split it at all? The answer is that in many cases, there might be no point to splitting it. If you are sure you will not need ScreenRatio ever again, it might be overkill. But if you suspect you might need any given functionality elsewhere again, it makes good sense. Suppose our function was 10-20 lines and much more complex. Then it makes good sense to encapsulate it into its own custom command or function with a simple interface. This will make scripts, where it is used, much easier to maintain.

Custom commands and functions are fully resolved through included files hierarchies. As more and more custom commands and functions are built, it will be a good idea to collect these in one or more include files. And if multiple administrators work on scripting, the encapsulation of complexity will make script construction a lot easier. One administrator knows how to create a script snippet that deletes files older than a specific number of days. The other administrators do not need to know how to do this - they can just call a command with two parameters.

If we put our example custom commands and functions presented here into its own included script file, we have effectively created a small script library. Our commands and functions are now encapsulated inside this include file, so our consuming script can be very simple:

Include MyScriptLib.fsh


MySqlBackup MSSQL$SQLEXPRESS,O:\SQLBackups\[Date]

MyDeleteFilesOlderThan O:\SQLBackups,90

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