The Script page is used to edit and evaluate scripted queries.
Topics:
- What are scripts used for?
- How do I run a script?
- How can I import data into Excel?
- Can I run scripts from the command line?
- How can I write scripts of my own?
- What functions does Query support?
- What functions does Network support?
- What functions does SNMP support?
- What functions does Table support?
- What functions does Chart support?
- What functions does Report support?
- What functions does Widget support?
- What function does A10 support?
- How do I output text in a script?
- How do I format a number as text?
- How do I format a date as text?
- How do I import external data into a script?
- How do I write data to files from a script?
- How do a run a shell command from a script?
See Also:
- Tutorial: Scripting Queries
- Tutorial: Advanced Scripting
- Tutorial: Creating Report Templates
- Tutorial: Integrating with a Customer Portal
What are scripts used for?
Scripts provide access to the traffic and topology databases. Scripts have many applications, including:
- Extracting data into a web-aware application such as Microsoft Excel.
- Extracting data into custom scripts written in other languages such as awk or perl.
- Creating specialized ad-hoc queries that are not supported by any of the Sentinel:Report>Query forms.
- Prototyping queries that will be used in new report templates.
How do I run a script?
To run a script, simply type or paste it into the Script form, then click Submit. If the query executes successfully, you will see the results, with the following options above:
- Back, return to the Script form.
- TXT, run the query again, but this time return only the text result. The URL for this page can be bookmarked or copied to another application.
- IQY, show the query in Microsoft Internet Query (.iqy) format, for use with Microsoft Excel.
How can I import data into Excel?
To load data into the cells of an Excel spreadsheet, follow these steps:
- Ensure that the "format" variable in the script is set to "html" rather than "csv", so that tabular output appears as HTML tables, rather than comma-separated values.
- Click Submit, then on the results page click IQY and save to a file such as "query.iqy".
- Open this file in Excel.
Note: If a password is required to access the Script page then you will have to provide login information when you run the query in Excel.
Can I run scripts directly from the command line?
For maximum efficiency and reliability, it is possible to execute scripts directly on the
server (bypassing the web server). Log in to the server and create a file containing your script (script.js
), then run the command:
/usr/local/inmsf/bin/query script.js
If you want to pass variables to the script then one or more -input arguments can be used. For example the the following command sets the variable interval to "last5minutes" and the variable truncate to "10" before invoking the script:
/usr/local/inmsf/bin/query -input "interval=last5minutes" -input "truncate=10" script.js
How can I write scripts of my own?
The scripting language is Javascript (version 1.6 with E4X). Describing the Javascript language is outside the scope of this document. If you need to learn more about Javascript, there are many books and web sites describing the language. There are a number of examples in the tutorial Scripting Queries.
The following extensions have been added to Javascript to support querying and reporting:
- Query, make queries against the traffic database.
- Network, access information about the network configuration.
- SNMP, make SNMP queries.
- Table, access tabular data.
- Chart, create charts.
- Report, collect charts, tables and text into reports.
- print/println printing functions.
- formatnumber number formatting functions.
- formatdate data formatting functions.
- readurl functions for retrieving external data.
- write functions to write data to a file.
- runcmd functions to execute shell commands.
What functions does Query support?
The Query class is used to access the traffic database.
Class Methods
- query = Query.trend(view,select,where,interval,group)
- query = Query.topN(view,select,where,interval,sort,truncate)
Instance Properties
- query.view = string
- query.select = string
- query.where = string
- query.interval = string
- query.group = string
- query.sort = string
- query.sortorder = "ascending" | "descending"
- query.truncate = integer
- query.nullsinkeys = boolean
Instance Methods
- table = query.run()
- table = query.run(function(row[]) {})
- table = query.run(function(row[],table) {})
Usage:
The view property must be one of the database views:
The select property is is a comma separated list of fields defined in the view. Fields marked as Key will be used to group results.
The fields sourceaddress, destinationaddress are polymorphic string fields that will follow the highest protocol layer addresses of each flow. That means they can sometimes be MAC addresses if it was layer-2 traffic, or even IPX, IPv6, Appletalk or DecNet addresses if those protocols are running in your network. The fields sourceport, destinationport have the same polymorphic behavior, as do clientaddress, serveraddress, clientport and serverport.
In contrast, the fields ipsource, ipdestination, ipclient and ipserver are only ever set for IPv4 flows. Otherwise they are equal to null. If you are filtering using subnets (e.g. "ipsource=10.1.1.0/24,10.1.2.0/24") or ranges ("ipsource=10.1.1.1-10.1.1.23") then you should always use these fields rather than the polymorphic ones. Similarly, fields such as tcpsourceport, tcpdestinationport, udpsourceport, udpdestinationport are only set if that protocol layer was present.
The where property is a filter that will be applied during the query to select specific data. You can only filter on attributes that are keys in the selected view.
A basic filter expression consists of the name of an attribute, an operator and a set of comma separated values. The allowed operators are:
- = equals
- != not equals
- ~ matches a reqular expression
- !~ does not match a regular expression
Expressions can be combined using brackets and the boolean operators:
- & boolean AND
- | boolean OR
The following examples illustrate typical where filters:
- ipsource = 10.1.1.23
- ipdestination != 10.0.0.0/24,10.0.1.0/24
- serverport = TCP:80,TCP:81,TCP:8080-8088
- sourcezone ~ research.*
- ipsource = 10.0.0.1 & ipdestination = 10.0.0.2
- ipsource = 10.0.0.1 & (sourceport = TCP:80 | destinationport = TCP:80)
- sourcezone = EXTERNAL | destinationzone = EXTERNAL
Note: The special zone EXTERNAL refers to addresses that aren't contained in any of the CIDRs specified using File > Configure.
WARNING Care should be taken if a value in a filter expression contains any of the following special characters: (, ), &, |, !, =, ~, ",', \, comma or space. If the value contains any of these characters then the whole value string can be enclosed in single or double quotes, or the special characters can be individually escaped with a \. The following examples show different ways of using the value "Research & Development" in filters:
- serverzone = "Research & Development", Sales
- clientzone = 'Research & Development'
- sourcezone = Research\ \&\ Development
- serverpath = ">>Research & Development>Data Center"
Note: Special characters typically occur because they are used in Zone or Group names when configuring Traffic Sentinel (see File>Configure). Care should be taken when filtering on zone, group or path attributes.
The interval property describes the time period for the query.
There are a number of predefined intervals, including:
- today
- yesterday
- thisweek
- lastweek
- thismonth
- lastmonth
- last5minutes
- last10minutes
- last15minutes
- last20minutes
- last60minutes
- last3hours
- last6hours
- last12hours
- last24hours
- last7days
- last30days
In addition, time intervals can be specified in the same format as the Unix at(1) command. If necessary the interval can be specified in the form start,stop where the interval runs from the start of the first inteval to the start of the second interval. The following examples demonstrate typical custom time intervals:
- now - 2hours
- last tuesday
- midnight + 45 minutes
- 10pm yesterday,9am today
- 20051230
- 20051230,20060104
- 20080418 18:00, 20080419 20:00
- 20080418 6pm, 20080419 8pm
The resolution used to compute time intervals is determined by the highest resolution token. For example "midnight + 45 minutes" has a resolution of minute and will generate a 1 minute interval starting at 15 minutes past midnight and "now - 2hours" has a resolution of hour and will generate an interval that falls on an hour boundary and extends for 1 hour.
The optional group property is used when computing time series to specify the size of each time grouping within the overall query interval.
The group size can be specified either as a number of minutes, or using special tokens. The following examples show typical group values:
- 5
- minute
- hour
- day
- week
- month
- year
The optional sort property is used to specify a Value field defined in the view that will be used to sort the result.
The optional truncate property controls the number of result rows.
The optional nullsinkeys property can be set to true to allow null keys to be included in the result.
If a callback function is provided to the query.run() method then the callback will be invoked for each result row instead of adding the row to the table. Using a callback function is useful if you are making a query that would generate a very large number of result rows. Each row can be examined without using the memory required to create the result table. The following example uses a callback function to count the number of rows in the result:
var max = 0; query.run(function() {count++});
What functions does Network support?
The Network class is used to access network configuration data and address mappings.
Class Methods
- network = Network.current()
- array[] = Network.uniqueMap(array[][])
- number[] = Network.countMap(array[][])
Instance Properties
- network.path = string
Instance Methods
- string = network.serverName()
- address = network.serverAddress()
- string = network.addressType(address)
- ipAddress = network.ipAddressFromName(string)
- string = network.nameFromIpAddress(ipAddress)
- string = network.pathForDeviceAddress(address)
- boolean = network.matchMask(ipAddress,cidr)
- boolean = network.isPrivateAddress(ipAddress)
- names[][] = network.dnsMap(ipAddress[])
- address[][] = network.addressMap(address[])
- interface[] = network.locationMap(address[])
- vendorname[] = network.vendorMap(macAddress[])
- macAddress[] = network.macMap(address[])
- macAddress[][] = network.interfaceToMacMap(interface[])
- vlan[] = network interfaceToVLANMap(interface[])
- ipAddress[][] = network.interfaceToDeviceIpMap(interface[])
- cidr[][] = network.interfaceToDeviceCidrMap(interface[])
- macAddress[][] = network.interfaceToDeviceMacMap(interface[])
- interface[] = network.neighborMap(interface[])
- asName[] = network.asMap(asNumber[])
- countryCode[] = network.countryMap(ipAddress[])
- countryName[] = network.countryNameMap(countryCode[])
- hostname[] = network.uuidToHostNameMap(uuid[])
- hostname[] = network.hostIdToNameMap(hostId[])
- hostId[][] = hostIdToMacMap(hostId[])
- path[] = network.hostIPtoPathMap(ipAddress[])
- path[] = network.subnetToPathMap(ipAddress[])
- macAddress[] = network.newLocations(date)
- address[] = network.newAddressMappings(date)
- ipAddress[] = network.newDNSMappings(date)
- address[] = network.newAddresses(date)
- macAddress[] = network.newMACAddresses(date)
- ipAddress[] = network.newIPAddresses(date)
- date[] = network.firstSeenMap(address[])
- date[] = network.lastSeenMap(address[])
- date[] = network.firstSeenMACMap(macAddress[])
- date[] = network.lastSeenMACMap(macAddress[])
- date[] = network.firstSeenIPMap(ipAddress[])
- date[] = network.lastSeenIPMap(ipAddress[])
- protocolName[] = network.protocolNameMap(protocol[])
- protocol[] = network.protocolNumberMap(protocolName[])
- cidr[] = network.subnets()
- agent[] = network.agents()
- hostId[] = network.hostIds()
- interface[] = network.interfaces()
- string = network.printPath()
- path = network.parent()
- path[] = network.children()
- path = network.enterprisePath()
- string = network.enterprise()
- path = network.sitePath()
- string = network.site()
- path = network.zonePath()
- string = network.zone()
- path = network.groupPath()
- string = network.group()
- path = network.agentPath()
- string = network.agent()
- path = network.interfacePath()
- string = network.ifx()
- boolean = network.noFlows()
- boolean = network.noCounters()
- boolean = network.agentDown()
- string = network.status(string)
- boolean = network.isAgent()
- boolean = network.isSwitch()
- boolean = network.isHost()
- boolean = network.isPhysicalHost()
- boolean = network.isVirtualHost()
- string = network.agentIP()
- string = network.sysDescr()
- string = network.sysObjectID()
- string = network.sysName()
- string = network.sysContact()
- string = network.sysLocation()
- number = network.sysServices()
- number = network.sysUpTime()
- boolean = network.isInterface()
- string = network.ifIndex()
- string = network.ifType()
- number = network.ifOperStatus()
- number = network.ifAdminStatus()
- number = network.ifDirection()
- number = network.ifSpeed()
- number = network.ifMtu()
- string = network.ifDescr()
- string = network.ifAlias()
- string = network.ifName()
- string = network.displayName()
- string = network.interfaceId()
- boolean = network.ifStackAvailable()
- interface[] = network.ifStackUp()
- interface[] = network.ifStackDown()
- string = network.dsClass()
- string = network.dsIndex()
- uuid = network.hostUUID()
- hostname = network.hostName()
- string = network.hostMachineType()
- string = network.hostOSName()
- string = network.hostOSRelease()
- hostId = network.hostParentId()
- adapter[] = network.hostAdapters()
- mac[] = network.hostMAC(adapter)
- number[] = network.threshold('frames'|'utilization'|'broadcasts'|'multicasts'|'errors'|'discards')
- table = network.entities()
- table = network.lldp()
- boolean = network.controlAdd('priority'|'limit'|'block',targetIP)
- boolean = network.controlAdd('priority'|'limit'|'block',targetIP,cookieString)
- table = network.controlList()
- table = network.controlList(allPathsFlag)
- table = network.controlList(allPathsFlag,allSourcesFlag)
- network.controlRemove(idString)
- boolean = network.controlApply()
- boolean = network.controlApply(blockFlag)
- table = network.quotas()
- table = network.quotas(allPathsFlag)
Usage:
The path property is used to scope many of the functions. A path refers to the enterprise>site>zone>group>agent>interface hierarchy specified using File > Configure. Omitting enterprise and site names is allowed. In addition an agent or interface can be specified without providing the full path. The following examples show typical path values:
- 10.0.0.254
- 10.0.0.254>1
- >>Office
- >>Office>Servers
The functions network.agents() and network.intefaces() return an array of path values. Scripts will often iterate over the array, setting the network.path attribute to each of the paths in order to extract information about all the agents or interfaces in the network.
The *Map functions are typically used to lookup information on all the elements of a column in a Table. These functions take in an array of values and return an array of results. Often the result of a map function will be inserted back into the table as a new column. Some of the map functions (e.g. network.addressMap()) are one to many functions (i.e. they return an array of arrays as a result). Inserting the result of a one to many map function as a table column is likely to cause an error since arrays are not typically allowed as table cells (arrays are are allowed if the column type is string). The utility functions Network.countMap() and Network.uniqueMap() are provided convert an array of arrays into a simple array of values. Network.countMap() counts the number of entries in each sub-array and return an array of numbers. Network.uniqueMap() returns the value if it is unique (i.e. the sub-array only contains one entry) or null otherwise. Finally, the network.addressMap() function is unusual in that it operates in two directions; it will map each layer-2 (MAC) address to one or more layer-3 addresses (e.g. IP, Appletalk, etc.) and it will map each layer-3 address to one or more layer-2 addresses.
The control* functions only have an effect if run at the command line or in a scheduled report. Multiply network.controlAdd() and network.controlRemove() operations can be made before calling network.controlApply(). The changes only take effect if the network.controlApply() function is called. The network.controlAdd() function will succeed only if the network.path has been set to an interface and the proposed control passes sanity checks (e.g. you cannot disable a switch uplink).
Note: interface, address, ipAddress, macAddress, asName, asNumber, cidr, protocol, protocolName, path, vendorName, countryName and countryCode "types" referred to in the function prototypes are all javascript strings, the different names are intended to clarify the form of the strings that needed. For example, a valid ipAddress would be "10.1.4.1".
What functions does SNMP support?
The SNMP class is used to query network devices using the SNMP protocol.
Class Methods
- snmp = new SNMP()
Instance Properties
- snmp.host = string
- snmp.port = number
- snmp.oid = oid[]
- value[] = snmp.value
- type[] = snmp.type
- snmp.version = "1" | "2c" | "3"
- snmp.community = string
- snmp.username = string
- snmp.authprotocol = "md5" | "sha1"
- snmp.authpassword = string
- snmp.privpassword = string
- snmp.retryintervals = string
- snmp.useconfig = boolean
- snmp.octetsformat = "hex" | "display" | "auto"
Instance Methods
- value[] = snmp.get()
- value[] = snmp.getnext()
Usage:
Set the host and the oid properties for the SNMP object to be retrieved, e.g. snmp.oid = "1.3.6.1.2.1.1.4.0" is the OID for sysContact. The get() function will return the value of the object corresponding to the oid. The getnext() function will retrieve the next object in the SNMP MIB and set the oid, value and type properties correspondingly.
The useconfig property (true by default) determines whether the SNMP settings will be taken from the configuration (see File > Configure) or will be provided directly. If useconfig = true then the SNMP version and credential settings will only applied if there is no configuration value applicable to the host. Setting useconfig = false overrides this behavior and only the values set in the script will be used.
The authorization credentials that need to be provided depend on the version property. If version is set to "1" or "2c" then the community property will be used. If version is set to "3" then the username, authprotocol, authpassword and privpassword properties will be used.
The retryintervals property can be set to an array of retry delays (expressed in milliseconds). A value of [20,40,100] would allow an initial request, one retry if a reply was not received within 20ms of the initial request, a second retry if no reply was received within 40ms of the second request and the query would fail completely if no reply was received within 100ms of the third request.
What functions does Table support?
The Table class is used to represent Query results and is also used to add tabular data to a Report
Class Methods
- table = new Table()
- table = Table.create(columnname[],columntype[])
Instance Properties
- number = table.nrows
- number = table.ncols
Instance Methods
- table.addColumn(name,type,value[])
- object = table.cell(r,c)
- row[] = table.row(r)
- column[] = table.column(c)
- table.insertColumn(name,type,column[])
- table.insertColumn(name,type,column[],columnIndex)
- table.deleteColumn(c)
- table.scaleColumn(c,number)
- table.addRow(array)
- table.deleteRow(r)
- table.sort(c,boolean)
- table.pivotTime(timeColumIndex,categoryColumnIndex,valueColumnIndex)
- table.pivotCategory(pivotColumnIndex,categoryColumnIndex,valueColumnIndex)
- table.printCSV(includeHeaders)
- table.printCSV(includeHeaders,dateFormat,numberFormat)
- table.printCSV(includeHeaders,dateFormat,numberFormat,language)
- table.printCSV(includeHeaders,dateFormat,numberFormat,language,country)
- table.printHTML(includeHeaders)
- table.printHTML(includeHeaders,dateFormat,numberFormat)
- table.printHTML(includeHeaders,dateFormat,numberFormat,language)
- table.printHTML(includeHeaders,dateFormat,numberFormat,language,country)
- table.printFixed(includeHeaders)
- table.printFixed(includeHeaders,width[],dateFormat,numberFormat)
- table.printFixed(includeHeaders,width[],dateFormat,numberFormat,language)
- table.printFixed(includeHeaders,width[],dateFormat,numberFormat,language,country)
Usage:
The following column types are defined:
- time
- address
- port
- string
- integer
- url
- double
- agent
- interface
- path
- protocol
- subnet
- as
The table print functions can optionally accept dateFormat and numberFormat arguments. The dateFormat string is described in formatdate and the numberFormat string is described in formatnumber. The width[] array in printFixed contains column widths in number of characters. Negative numbers indicate right justified columns.
What functions does Chart support?
The Chart class is used to represent data that will be displayed as a chart in a report or widget. Typically a chart is created by running a Query and selecting columns from the resulting Table.
Class Methods
- chart = Chart.multiSeries(type,title,table,xlabel,categoryColumnIndex,yLabel,valueColumnIndex[])
- chart = Chart.singleSeries(type,title,table,xLabel,categoryColumnIndex,yLabel,valueColumnIndex)
- chart = Chart.singleValue(type,title,yLable,value,minValue,maxValue,marginalValue,criticalValue)
Instance Properties
- chart.width = number
- chart.height = number
- chart.horizontal = boolean
- chart.stack = boolean
- chart.threeD = boolean
- chart.alpha = number (0.0 <= alpha <= 1.0)
- chart.backgroundColor = string
- chart.plotColor = string
- chart.axisColor = string
- chart.tickmarkColor = string
- chart.gridColor = string
Usage:
Supported values for type are:
- bar, horizontal and vertical stacked or grouped bar charts.
- pie, single or multi-pie plots.
- trend, line or area trend charts (Note: category column must be a time column).
- line, line or area line chart.
- gauge, single value plotted on a gauge.
- thermometer, single value plotted on a thermometer.
The following color values are defined: "red", "black", "blue", "cyan", "dark_gray", "gray", "green", "light_gray", "magenta", "orange", "pink", "yellow", "white", "dark_blue", "dark_cyan", "dark_green", "dark_magenta", "dark_red", "dark_yellow", "light_blue", "light_cyan", "light_green", "light_magenta", "light_red", "light_yellow", "very_dark_blue", "very_dark_cyan", "very_dark_green", "very_dark_magenta", "very_dark_red", "very_dark_yellow", "very_light_blue", "very_light_cyan", "very_light_green", "very_light_magenta", "very_light_red", "very_light_yellow".
Custom colors can be defined using the notation "RRR,GGG,BBB" where RRR, GGG and BBB are values between 0 and 255.
Note: Default chart settings can be specified in the global.prefs file.
What functions does Report support?
The Report class is used to add headings, paragraphs, tables and charts to reports.
Class Methods
- report = Report.current()
Instance Methods
- date = report.getTime()
- boolean = report.isScheduled()
- report.sendEvent(type,severity)
- report.heading(string)
- report.paragraph(string)
- report.chart(chart)
- report.table(table)
- report.storeTable(cookie,table)
- table = report.retrieveTable(cookie)
Usage:
Valid event types are threshold, security and status. Valid event severities are inform, warn and severe.
Note: the report.sendEvent(), report.storeTable() and report.retrieveTable() methods only have an effect when the script is run as part of a scheduled report.
What functions does Widget support?
The Widget class is used to add tables and charts to widgets.
Class Methods
- widget = Widget.current()
Instance Methods
- date = widget.getTime()
- widget.chart(chart)
- widget.table(table)
What functions does A10 support?
The A10 class provides access to an A10 Networks IDsentrie server. The A10 server keeps track of the mappings between network addresses and user IDs. This information is useful for identifying the user IDs associated with suspicious activity, or tracking the activity of a selected user. Default communication settings can be specified in global.prefs file.
Class Methods
- a10 = new A10()
- a10 = new A10(server)
- a10 = new A10(server,partner_id,partner_passcode)
- a10 = new A10(server,partner_id,partner_passcode,protocol)
- a10 = new A10(server,partner_id,partner_passcode,protocol,port)
Instance Properties
- a10.server = string
- a10.partner_id = string
- a10.partner_passcode = string
- a10.protocol = "http" | "https"
- a10.port = integer
Instance Methods
- table = a10.ipToId(ipaddress,starttime,endtime)
- table = a10.macToId(macaddress,starttime,endtime)
- table = a10.idToIp(userid,starttime,endtime)
Usage:
The start and end times are expressed as javascript Date instances.
The result tables have the form:
userid,starttime,endtime
or
address,starttime,endtime
How do I output text in a script?
The print and println functions are used to output text from a script.
- print(string)
- println(string)
The print function does not start a new line, so successive calls to print will result in text being concatenated into one long line. The println function starts a new line after each call.
Note: Print functions have no effect if the script is being run as part of a report template, the report.paragraph() function should be used instead.
How do I format a number as text?
The formatnumber function is used to convert a number into formatted text.
- string = formatnumber(number,formatString)
- string = formatnumber(number,formatString,language)
- string = formatnumber(number,formatString,language,country)
The formatString follows the Java DecimalFormat syntax. The country and language codes follow the Java Locale specification.
How do I format a date as text?
The formatdate function is used to covert a date into formatted text.
- string = formatdate(date,formatString)
- string = formatdate(date,formatString,language)
- string = formatdate(date,formatString,language,country)
The formatString follows the Java SimpleDateFormat syntax. The country and language codes follow the Java Locale specification.
How do I import external data into a script?
The readurl function is used to import data.
- string = readurl(url)
- string = readurl(url,"get",user,password)
- string = readurl(url,"post",contentType,content)
- string = readurl(url,"post",contentType,content,user,password)
Note By default only http and https protocols are allowed in the URLs. Reading of files is only allowed when scripts are run from the command line or when explicitly enabled by setting the report.readurl.protocol.file variable in the global.prefs file.
How do I write data to files from a script?
The write function is used to write data to a file.
- write(filename,string)
- write(filename,table)
- write(filename,chart)
The filename determines the format of a chart file. If the filename ends in ".gif" then a GIF image will be written, if the filename ends in ".jpg" then a JPEG image will be written, otherwise the image will be stored in PNG format.
Tables will be written as html tables and strings are written as simple text files.
Note: The write function can only be used when scripts are run from the command line or when explicitly enabled by setting the report.write.allow variable in the global.prefs file.
How do a run a shell command from a script?
The runcmd function is used to execute a shell command.
- result = runcmd(cmd)
- result = runcmd(cmd[])
- result = runcmd(cmd[],envp[])
- result = runcmd(cmd[],envp[],dir)
All the arguments are strings. Entries in the envp array are environment variables of the form "name=value". The dir argument is a string specifying the working directory for the command. The runcmd functions follow the syntax of the Java Runtime.exec methods.
The runcmd function returns an object with three attributes:
- result.status the integer return code.
- result.stdout an array of strings containing lines of output from the command.
- result.stderr an array of strings containing lines of error messages from the command.
Note: The runcmd function can only be used when scripts are run from the command line or when explicitly enabled by setting the report.runcmd.allow variable in the global.prefs file.