Scripting Reference
With KeyConfigure's embedded JavaScript engine, you can write scripts that access, read, and modify the basic objects in KeyConfigure such as computers, policies, and products. You can also access and open new windows containing these objects, retrieve information from external sources using standards like ODBC and LDAP, and access network resources like web servers and e-mail.
This document provides detailed information on all of the objects and methods available within the scripting environment.
A separate Scripting Tutorial describes how to create JavaScript bundles that will be added to KeyConfigure's Tasks menu and to contextual menus as appropriate. It gives a walk-through of several scripts, starting from the most basic through a more complex script that prompts the user and makes changes to selected computers.
The scripting functionality uses Duktape, a JavaScript engine developed by Sami Vaarala that is a model of good design, coding, and documentation.
Global Objects
The program hosting a script will add some objects to the script's global namespace. These objects expose information to the script and provide access to resources related to the script.
app
The app object is managed by the program hosting the script. The properties available in the object will change depending on the hosting program and the state of the user interface.
name
String
The name of the program hosting the script, e.g., “KeyConfigure”
version
String
The version of the program hosting the script, e.g., “7.5.0 (Duktape 2.1.0)”
selection
KSView
A KSView object containing the selection of the frontmost window. See
KSView class for information on using objects of this class. This property will not be defined if there is no selection, or if the frontmost window does not contain objects of the type that the script is targeting. See
Manifest properties, specifically the
target property, for how to indicate the type of object a script expects in the selection.
progress
object
An object that controls the progress feedback for the running script. See
Progress feedback pattern for information on using this object, and
app.progress object for a description of its methods. For most simple scripts, the default progress behavior is sufficient. More complex scripts can use the
progress object to give hints so the progress indicator properly reflects the various stages during the script's operation.
bundle
The bundle object provides information about the script bundle, and access to the bundle resources. If the script is not contained within a bundle, this object will not be defined.
manifest
object
The manifest object loaded from the bundle's
manifest.json file. See
Manifest properties for the possible properties of this object.
The simplest manifest looks like this:
{
id: "org.domain.my-script",
name: "My Script",
script: "script.js"
}
load(String name)
object
Load the file named name from the bundle's support folder. The result depends on the filename extension. If the file cannot be parsed according to its type an error will be thrown.
To load a JavaScript object from a JSON-formatted file:
var myobj = bundle.load("someobj.json");
To load a text file and read it line-by-line:
var myfile = bundle.load("something.txt");
myfile.forEach(function (line) {
});
To load a CSV file with a header and read it line-by-line:
var myfile = bundle.load("something.csv");
myfile.forEach({
header: true,
callback: function (row, header) {
}
});
To parse and execute a JavaScript file within the context of the calling script:
var res = bundle.load("helper.js");
console
The console object provides most of the functionality of console objects in other JavaScript environments. Mostly it is used to write diagnostic information to a log file. The location of this log file depends on the program hosting the script. For KeyConfigure on OS X the output is written to the system.log. KeyConfigure on Windows writes the output to the Windows Event log. The ks-jst command line program writes output to stderr.
assert(boolean expr)
assert(boolean expr, String msg)
Log a msg if expr is false.
To test a condition and log a message when that condition fails:
var flan = 2;
console.assert(flan <= 1, "too much flan");
This is essentially equivalent to:
var flan = 2;
if (!(flan <= 1))
console.error("too much flan");
clear()
No-op, supported for cross-compatibility
count(String label)
Log the number of times this line has been called with the given label
debug(String msg)
Log msg if logging output level is debug (7) or higher
error(String msg)
Log msg if logging output level is error (3) or higher
info(String msg)
Log msg if logging output level is info (6) or higher
log(String msg)
Log msg if logging output level is notice (5) or higher
time(String label)
Start a timer with the given label
To time a section of code and log the elapsed time:
console.time("my timer");
console.timeEnd("my timer");
timeEnd(String label)
Stops the timer with the given label and logs the elapsed time in seconds since its start
See time above.
warn(String msg)
Log msg if logging output level is warn (4) or higher
localStorage
The localStorage object provides persistent storage if the storage file has been provided to the host program. For bundled scripts, there must be a template localStorage.json file in the bundle's storage directory, otherwise values written to this object will not persist. For non-bundled scripts hosted by ks-jst, a localStorage.json file must be specified with the -s option.
For bundled scripts, if there are other storage template files in the bundle's storage directory, corresponding Storage objects will be added to the global scope. The name of the object is derived from the file name. It will be the last component of the file name before the extension. So a storage template file named “sample.testStorage.json” will create a new storage object named “testStorage”. If there are multiple storage template files that would result in the same object name, only one will be used.
For properties and methods of localStorage and other storage objects, see Storage class.
Global Methods
The program hosting a script will add some methods to the script's global namespace. These methods provide some useful utility functions and give a way to control behavior of the host program.
alert(String msg, boolean cancel)
boolean
Display an alert with the message msg. In the second usage, if cancel is true a Cancel button will be shown in addition to the OK button. If the user clicks Cancel the return result will be false. In all other cases true is returned.
To show an alert with an
OK button:
alert("Your changes have been accepted.");
To show an alert with
OK and
Cancel buttons:
if (alert("Changes will be saved.", true)) {
} else {
}
decode(String msg, String encoding) 7.5
String
Decode an encoded string into its original value. There are a few data values that will throw an error when decoding is attempted. This is for security reasons, and should not occur for common usage. If the original data is a valid printable string, decoding should always succeed. The default is to use base64 encoding. Supported encoding values are:
Encoding | Description |
“hex” | msg is a string of hexadecimal digits (0-9, A-F) |
“base32” | msg is a base32 string (RFC 4648 section 6) |
“base64” | msg is a base64 string (RFC 4648 section 4 or 5) |
“base64url” | same as “base64” |
To decode valid base64 encoded data:
var msg = decode("SGVsbG8sIFdvcmxkIQ==");
digest(String msg, String encoding) 7.5
digest(String alg, String msg)
digest(String alg, String msg, String encoding) 7.5
digest(String hmac_alg, String secret, String msg)
digest(String hmac_alg, String secret, String msg, String encoding) 7.5
String
Calculate a hash of
msg string, using the
alg algorithm. The first two styles of this method compute the MD5 hash. The second two styles compute the hash given by
alg. The third two styles compute the HMAC using the given hash algorithm and
secret. When the encoding is not specified, the hash is returned as a hexadecimal string with length according to the algoritm. Supported algorithms are:
Hash Algorithm | Hash size | HMAC |
MD4 | 16 | unsupported |
MD5 | 16 | HMAC-MD5 |
SHA1 | 20 | HMAC-SHA1 |
SHA224 | 28 | HMAC-SHA224 |
SHA256 | 32 | HMAC-SHA256 |
SHA384 | 48 | HMAC-SHA384 |
SHA512 | 64 | HMAC-SHA256 |
SHA512-256 | 32 | HMAC-SHA512-256 |
SHA512-384 | 48 | HMAC-SHA512-384 |
Supported encoding values are:
Encoding | Description |
“raw” | digest is returned as an octet buffer |
“hex” | digest is encoded as a string of hexadecimal digits (0-9, A-F) |
“base32” | digest is encoded as a base32 string (RFC 4648 section 6) |
“base64” | digest is encoded as a standard base64 string (RFC 4648 section 4) |
“base64url” | digest is encoded as a URL-safe base64 string (RFC 4648 section 5) |
To calculate the SHA256 digest of a string:
var hash = digest("SHA256", "Hello, World!");
To calculate the HMAC of a secret and string using the SHA1 hash algorithm and encode it in base64:
var hmac = digest("HMAC-SHA1", "secret", "Hello, World!", "base64");
encode(String msg, String encoding) 7.5
String
Encode a string into a text-only format. This is useful for things like Basic Authentication headers in HTTP requests. The default is to use base64 encoding. Supported encoding values are:
Encoding | Description |
“hex” | msg is encoded as a string of hexadecimal digits (0-9, A-F) |
“base32” | msg is encoded as a base32 string (RFC 4648 section 6) |
“base64” | msg is encoded as a standard base64 string (RFC 4648 section 4) |
“base64url” | msg is encoded as a URL-safe base64 string (RFC 4648 section 5) |
To encode any string to a base64 encoded string:
var blob = encode("Hello, World!");
Write a line of text to an output file. When the script is running in KeyConfigure, the first call to print will prompt the user for a file into which the text should be written. Subsequent calls to print from the same script will also write to this file. If the user cancells the save dialog, the text will be discarded without being saved. Scripts running in ks-jst will print to stdout by default.
To write a line of text to a file:
print("a line of text");
boolean
Display a prompt to the user with fields as defined by a prompt object. The dialog will be “modal”, so other windows in KeyConfigure will not be accesible. To use a non-modal dialog, see
Non-modal user prompt pattern. For a list of field types that can be presented in the dialog, see
Prompt Field Types.
info object
fields
Array
The list of fields to display in the prompt dialog. Field types are described in
Prompt Field Types.
id
String
A unique value for use with unattended execution of the script. This should be a uniform type identifier in reverse DNS format using your organization's domain name. For bundled sripts it is recommended that the script id be use along with a suffix unique within the script (in case there are multiple prompts), for example, “org.domain.my-script.first-prompt”.
title
String
A string to be used for the prompt dialog's title.
To present some text along with a checkbox to the user:
var answer = prompt({
fields: [
{
id: "message",
label: "Enter the Message:",
type: "text"
},
{
id: "frobnicate",
label: "Run the Frobnication protocol",
type: "bool"
}
]
});
if (answer) {
alert(answer.message);
if (answer.frobnicate) {
}
}
quit(String msg)
Quit the script anywhere in your code, with an optional termination message shown to the user. It is not necessary to call this method at the end of your main script, and is usually only needed in abnormal situations. Scripts should be designed to run to completion.
To quit the script immediately from anywhere:
quit();
random(number n)
random(String s, number length)
number or String
Generate a random value. The first style of this method retuns a randomly generated number 0 ≤ x < 1. The second style returns a random whole number 0 ≤ x < n. The third style creates a random string of length characters chosen from s.
To generate a random whole number from 0 to 9:
var x = random(10);
To generate a random 16-digit hexadecimal string:
var s = random("0123456789ABCDEF", 16);
Put the script thread to sleep for millisecs milliseconds (1/1000 of a second). For scripts that run short-term tasks it is not usually necessary to sleep at any point. Scripts that keep running for longer periods of time (perhaps to periodically check a condition) should sleep while looping.
To put the script thread to sleep for 3 seconds:
sleep(3000);
Classes
Several classes are defined by the host program. There are classes for the various KeyServer-related data types, and classes that are based on widely used specifications. These classes are all implemented in native code for performance, and as a bridge between the host program and the script. Any complex script can define its own set of classes as well, using normal JavaScript patterns.
KSFile 7.4
An object of the KSFile class represents a text file that can be read line-by-line. Objects of this class cannot be created by the script, instead they are obtained via the bundle.load() method, or through a user prompt field with type “file”.
Files with the “.csv” extention are parsed so that each call to the callback function receives one complete logical record, even if the record spans multiple lines in the file. Furthermore, each record is parsed into separate values and passed as an array.
forEach(function func)
forEach(object info)
boolean
Read the lines of a file, calling the provided function for each line. The first style of this method just specifies the callback function. The function accepts one argument, a
String that contains the current line. The second style of this method is passed an object that provides the
callback function as well as a
context that will become the function's
this value, and optional functions that will be called before and after the file is read.
info object
context
object
The callback (and commence, complete) function's this value.
format
String
The format to assume when parsing this file. If this property is not provided, the format is considered plain text and will be processed one entire line at a time. If a valid format is provided, each line of the file will be parsed into an array of values. This array is passed as the first parameter to the
callback function. Possible formats are:
Value | Format |
“csv” | Comma Separated Values |
“tab” | Tab Separated Values |
header
boolean
A flag indicating that the file starts with a header line. The callback function will not be called for this line. Instead, the line will be passed as the callback function's second parameter for all other lines in the file. It will also be passed into the commence and complete functions.
function callback(String line [, String header])
function callback(String[] line [, String[] header])
boolean
The function that is called for each line in the file. Return true to stop reading the file.
function commence([String header])
function commence([String[] header])
The function that is called once before reading the file.
function complete([String header])
function complete([String[] header])
The function that is called once after reading the file.
To iterate over the lines in a file:
var counters = { total: 0, empty: 0 };
file.forEach({
context: counters,
callback: function (line) {
this.total++;
if (!line.length)
this.empty++;
}
});
KSImport 7.4.0.8
The KSImport class is used to bulk-import data into a table on the server. Currently the KSComputers, KSDevices, and KSPurchases tables can be the target of an import.
For communication with the server, the KSImport class uses the host program's default connection. With KeyConfigure, this is the connection of the current administrator. For ks-jst see the command line options.
KSImport(String table, String mapping)
KSImport(String table, object mapping)
object
Create a new KSImport object that can be used to import data into
table according to the instructions in
mapping. The first style of this method specifies the mapping by name, which refers to importing mapping instructions that were created in KeyConfigure and saved on the server. In the second style, the mapping is provided directly. The supported values for
table are:
Value | Table |
“computer” | KSComputers |
“device” | KSDevices |
“purchase” | KSPurchases |
To create a KSImport object for importing into the KSPurchases table, using a mapping that was created in KeyConfigure:
var imp = new KSImport("purchase", "My Purchase Schema");
close()
Close an open import. Once the import is closed it cannot be used to submit new records until it is opened again. A new import using the same table and mapping can be initiated using the open() method.
open()
open(String[] fields)
boolean
Open the KSImport object for importing a given field set. The first style of this method does not specify the list of fields. Instead, fields and values will both be given in each call to submit. The second style of this method gives the array of field names that will be used in subsequent calls to submit.
status()
object
Retrieves the status record for the most recently completed
open or
submit operation. The returned object indicates the priority of the error, the record number (for convenience), summary information, and details for sub-record information. Values for the
priority and
level properties are:
Priority | Level | Meaning |
0 | “emergency” | source of data could not be established |
1 | “alert” | source of data is malformatted |
2 | “critical” | failure that prevents further importing |
3 | “error” | failure on specified record |
4 | “warning” | a minor issue that requires attention |
5 | “notice” | a notable condition during normal processing |
6 | “info” | extra information on successful processing |
7 | “debug” | a diagnostic message |
Getting the status for a submit might look like this:
imp.submit(...);
var stat = imp.status();
if (stat && stat.priority <= 4) {
var desc = stat.summary
|| (stat.details && stat.details[0])
|| { code: "unspecified" };
print("error " + desc.code + " on record " + stat.record + ": " + desc.comment);
}
The object returned from
status() has the general format shown below. The object will always have either a
summary property or a
details property, and could have both. The
summary property gives information on the entire record, while the
details property is an array of items pertaining to individual fields within the record. The main
code,
priority, and
level values always reflect the status with the most priority (lowest numerical value in the priority property).
{
record: 1,
code: 4211,
priority: 4,
level: "warning",
summary: {
code: 6201,
priority: 6,
level: "info",
comment: "create Acme Widget 2017 20 Node"
},
details: [
{
code: 4211,
priority: 4,
level: "warning",
field: "purchaseCurrency",
value: "Federation Credits",
comment: "unmapped string 'Federation Credits' for enumerated field 'purchaseCurrency'"
},
...
]
}
This example shows that the record was imported successfully. The status object has an overall priority of 4 (warning), which comes from the first detail item.
submit(object values)
submit(Array values)
KSObject
Submit a record to be imported. The first style of this method takes an object where the field names and values are given as properties. In this case, the open() call is not passed an array of fields, since each submit contains the given record's fields. The second style of this method takes an array of values, which align with the field names provided in the open(...) call.
To submit a record for import:
var imp = new KSImport("purchase", {
Mappings: {
"orderRecipient": "Recipient",
"purchaseOrderID": "PO Number",
"purchaseDescription": "Description",
"purchaseQuantity": "Units",
...
},
...
});
imp.open([
"PO Number",
"Recipient",
"Description",
"Units",
...
]);
imp.submit([
"27B/6",
"Harry Tuttle",
"Bentley WaterCAD",
1,
...
]);
imp.close();
Alternatively, to submit a record using an object with properties:
imp.open();
imp.submit({
"PO Number": "27B/6",
"Recipient": "Harry Tuttle",
"Description": "Bentley WaterCAD",
"Units": 1,
...
});
imp.close();
KSJournal 7.4
The KSJournal class provides a mechanism for writing events to the Admin Journal. Events are grouped into “topics” according to their type and code, and optional subject table. Events can be written to an existing topic, or a new topic can be “registered” using the static register() method of this class.
For communication with the server, the KSJournal class uses the host program's default connection. With KeyConfigure, this is the connection of the current administrator. For ks-jst see the command line options.
KSJournal(String type, String code)
KSJournal(String type, String code, String table)
object
Create a new KSJournal object that can be used to submit events to the Admin Journal.
action
String
The action that is expected for this event. This setting is configurable by the KeyServer admin, so it might change from one event to another. The value will only be valid after either
prepare() or
test() is called on the event object. Possible values are:
Value | Action |
“disabled” | the event will not be written to the journal |
“enabled” | the event will be written to the journal without comment |
“request” | a comment is requested for this event |
“require” | a comment is required for this event |
autocommit
boolean
Reflects the autocommit option for the topic as it was set when the topic was created. The value will only be valid after either prepare() or test() is called on the event object.
autoresolve
boolean
If true, this event will be added to the Journal history upon commit. If false, this event requires acknowledgement by an admin before being moved to the history. The value will only be valid after either prepare() or test() is called on the event object.
combine
boolean
Reflects the combine option for the topic as it was set when the topic was created. The value will only be valid after either prepare() or test() is called on the event object.
headless
boolean
Reflects the headless option for the topic as it was set when the topic was created. The value will only be valid after either prepare() or test() is called on the event object.
summarize
boolean
If true, events in the same topic can be summarized by a single event. If false, each event will appear separately in the Journal. The value will only be valid after either prepare() or test() is called on the event object.
cancel()
Cancel the event, removing it from the Journal even if it has been committed. This only applies to events that are not resolved or acknowledged, so a topic that is autoresolve will not be cancellable once it has been committed. If multiple events have been prepared, only the most recent will be cancelled. Use this method when an event has been prepared but the user cancels the associated activity.
commit()
commit(number result)
commit(String comment)
commit(number result, String comment)
boolean
Submit a prepared event to the Journal. It is not necessary to commit() events for topics that have the autocommit flag set to true, although doing so does not have any unwanted effects. Events that have yet to be committed show up as “pending” in the user interface. However, an event that is not committed (or cancelled) by a script will be automatically committed when the script completes. The first style of this method simply commits the event. The second style sets a result code in the event (negative values indicate a failure). The third style attaches a comment to the event, and the fourth style allows for both a result and a comment to be provided.
To prepare and submit a basic event to the Journal:
var jour = new KSJournal("samp", "done");
jrnl.prepare({
level: "notice",
comment: "The deed is done"
});
jrnl.commit();
prepare(object event)
boolean
Prepare an event to be submitted to the Journal. The event will be added to the topic indicated when this object was created. Calling this method more than once on a KSJournal object is allowed, and will either summarize the multiple events or will submit separate events for each time
prepare() is called.
event object
agent
String
The name of the agent submitting the event. This defaults to the name of the connected administrator, and should usually only be set for server-side background scripts.
attribute
String
An attibute of the subject of the event that is relevant to the event. Only include this property if it is important to distinguish various similar events based on different attributes of the same subject. When the topic's summarize flag is true, multiple simultaneous events with different attributes will be summarized in a single event.
comment
String
A comment to attach to the event. If a comment is provided here, the event's action will never be “request” or “require”. The comment can be omitted here and later provided to the commit() method.
level
String
The level of importance of the event. Possible values are:
Value | Meaning |
“emergency” | a condition that will cause loss of service |
“alert” | a condition that is preventing normal service |
“critical” | a condition that is preventing the server from accomplishing an important task |
“error” | a failure that should be fixed |
“warning” | a minor issue that requires attention |
“notice” | a notable event during normal service |
“info” | an unimportant event providing extra information |
“debug” | a diagnostic event (use only for testing scripts) |
resolvable
boolean
A flag indicating that the event has a resolve handler.
section
number
The ID of the section associated with this event. Set to 0 to indicate the Enterprise, or omit this property to indicate that no section applies.
subject
String or object
The subject of the event. Normally when this property is included it is set to a
KSObject. When the topic's
summarize flag is
true, multiple simultaneous events with different subjects will be summarized in a single event.
subject object
id
String
The unique identifier of the subject of this event.
name
String
The name of the subject of this event.
table
String
The table from which the subject comes.
register(object topic)
boolean
Create a new journal topic that can have events added to it. This method can be called directly on the KSJournal class without instantiating a new object.
topic object
type
String
The four-letter type of this topic. Topics that have the same general purpose should share the same type. This allows for easier filtering of events in the Journal.
code
String
A four-letter code that distinguishes this topic from other topics of the same type.
table
String
If events in this topic include a subject, this field indicates the table from which the subject comes. Using this field, different topics that share the same type and code can be created for each applicable table.
category
String
An optional four-letter category for this topic. The category is used to organize topics for display in the user interface. For topics registered by scripts, the default and recommended category is “scpt”.
action
String
The initial setting for the action to take when a new event in this topic is added to the Journal This setting can be changed by the KeyServer admin. Possible values are:
Value | Action |
“disabled” | the event will not be written to the journal |
“enabled” | the event will be written to the journal without comment |
“request” | a comment is requested for this event |
“require” | a comment is required for this event |
headless
boolean
A flag indicating that events in this topic will be submitted when it is not possible to display a user interface. Events in a headless topic will never have an action that might prompt for a comment. Topics should only be marked as headless when absolutely necessary, since this setting restricts the options available to the KeyServer admin.
autocommit
boolean
A flag indicating that events in this topic will be immediately committed upon being submitted. Setting this option can reduce the amount of network traffic and other resource usage for topics that are used for signaling that a condition has been detected. It is not necessary to commit() journal entries for auto-committed topics.
autoresolve
boolean
A flag indicating that events in this topic will be moved to the Journal history after beeing committed. Topics whose events that should be acknowledged by a KeyServer admin should not set this flag. This flag can be changed by the KeyServer admin.
summarize
boolean
A flag indicating that events in this topic that have not been resolved or acknowledged can be summarized into a single event when the events occur at the same time. This flag can be changed by the KeyServer admin. It corresponds to the “Batch” setting in the user interface.
combine
boolean
A flag indicating that events in this topic that have not been resolved or acknowledged can be combined into a single event, even if the events occur at different times. Set this flag when the events of a topic might occur multiple times before an admin can acknowledge them, but there is no need to record each of these events separately.
name
String
The name of the topic, displayed in the user interface.
description
String
A more detailed description of the topic.
To register a topic with the KeyServer:
KSJournal.register({
type: "samp",
code: "done",
action: "enabled",
name: "Sample Script has completed"
});
test()
number
Test the action of the journal topic for the event. It is more efficient to
prepare() the event first in order to get its
action value and other flags, but in some cases it is useful to retrieve and test the action before the event is prepared.
Result | Meaning |
< 0 | the topic is unknown or an error occurred |
0 | the topic is disabled; event will not be recorded |
1 | the topic is enabled and can be submitted without comment |
2 | the topic is enabled and a comment is requested |
3 | the topic is enabled and a comment is required |
KSObject 7.4
The KSObject class is used to represent a KeyServer object like a computer or a policy.
KSObject(String table, String id)
object
Creates a new KSObject that represents the object identified by id from the specified table. If the object is not available, an exception is thrown.
id
String
The unique identifier for this object. Format and interpretation of this property is specific to the object type (table). This property can be saved and then used again later to find the same object.
name
String
The name of this object. For some object types the name and the ID are the same. In these cases it is not possible to modify the name.
table
String
The name of the table from which this object comes, e.g., “computer” or “policy”.
object-specific properties
String, number, boolean
Each object type has a different set of properties, with names roughly derived from the SQL column names used in ksODBC and for exported data.
A list of the properties for a specific object can be gathered using a simple approach like the following:
var view = new KSView("computer");
view.select();
view.forEach(function (obj) {
for (var key in obj)
print(key);
return(true);
});
commit()
boolean
Save changes made to an object. If multiple changes are made to an object, you only need to call this method once.
To set the
name and
notes properties of a policy and then save the changes:
policy.name = "XYZWrite Policy";
policy.notes = "Name changed at " + (new Date()).toString();
policy.commit();
remove()
boolean
Remove the object from KeyServer's data. Once an object has been removed it should not be used again by the script. In many cases it is better to change an object's status instead of removing it from the data altogether. For example, computers can be marked as Excluded, programs and products can be Ignored, and purchases and policies can be deactivated. Do not remove an object if you want to see it in reports on historical activity.
KSQuery 7.4
The KSQuery class is used to make low-level queries directly to the server's internal tables. Generally it is easier to use KSView and KSObject if the required information is available in that way.
KSQuery()
KSQuery(String creds)
KSQuery(String name, String password)
KSQuery(String name, String password, String host)
object
Creates a new KSQuery object. The first style of this constructor will use the existing connection to the server, if available. This connection is always available to scripts running in KeyConfigure. In the second style of the constructor the login information is supplied as one string in the format “user:password@host”. The remaining styles of the constructor take the login information as separate strings. If the host value is not given, localhost will be used.
command(String cmd)
boolean
Prepare a raw KSQL command. Results of the command are processed by calling the execute() method.
execute(function process)
execute(function process, function complete)
execute(object info)
boolean
Execute the command or query, passing the results to a callback function. The first style of this method takes just the
callback function that will be called for each result row. The function will be passed one argument, an object containing properties that correspond to the requested fields. The second style of this method takes the
callback function and also a
complete function that will be called when the command or query has finished. The
complete function is passed two arguments: a numerical result and a
String containing the KSQL “final” status. The third style of this method is passed an object that provides the
callback function, the
complete function, and a
context that will become the functions'
this value.
info object
context
object
The callback function's this value.
function callback(object row)
boolean
The function that is called for each result row. Return true to stop processing rows.
function complete(String final)
The function that is called once the operation has finished.
query(String table, String fields, String filter)
boolean
Prepare a KSQL query on the given table for the requested fields, filtered according to the filter string. Results of the query are processed by calling the execute() method.
KSView 7.4
An object of the KSView class contains a list of KSObjects. New views can be created for KSObjects of a specified type, such as computers or policies, and then populated with a filter, an array of object ids, or a list of values to match against a particular property. The view can be iterated over to access each object it contains.
The contents of a view can be changed as needed without creating a new view object. Each time select() is called, the current contents of the view are replaced with the newly selected objects.
KSView(String table)
object
Creates a new KSView that can contain objects from table. The view is initially empty. Objects can be added using the select() method.
length
number
The number of objects contained in the view
table
String
The name of the table that the objects in the view come from, e.g., “computer” or “policy”
find(String id)
find(number id)
KSObject
Find a specific KSObject given its id. Most KSObjects have ids that are represented as Strings, but some have ids that are numbers, depending on the table they come from. For example, folders have number ids.
forEach(function callback)
forEach(object info)
boolean
Iterate over the objects contained in the view, calling the provided function for each object. The first style of this method just specifies the callback function. The function accepts one argument, the
KSObject, and can return
true to stop the iteration. The second style of this method is passed an object that provides the
callback function as well as a context that will become the function's
this value.
info object
context
object
The callback function's this value.
order
String or String[]
An option colomn or array of columns to sort the view. Objects will be passed to the callback in this order.
function callback(KSObject obj)
boolean
The function that is called for each object in the view. Return true to stop the iteration.
To iterate over the objects in a view:
var total = 0;
view.forEach(function (obj) {
total++;
});
Alternative way to iterate over the objects in a view, with the view objects sorted by
name and then
ID:
var counters = { total: 0 };
view.forEach({
context: counters,
order: [ "name", "id" ],
callback: function (obj) {
this.total++;
}
});
select()
select(boolean all)
select(String filter)
select(Array idlist)
select(object info)
boolean
Populate a view with a set of objects from the view's
table. The first style of this method places all objects in the
table into the view. The second style will place all objects (
true) or no objects (
false) into the view. The third style accepts a
String that is used as a filter to choose which objects to include in the view. The fourth style chooses the objects whose
ids are listed in an array. The last style uses an object that provides a field name and an array of values, and includes objects where the given field has one of the listed values.
info object
field
String
The field of the object to compare with the list of match values.
match
String[]
The list of values to match against the given field in each object.
To select all objects that have the name “Rosencrantz” or “Guildenstern”:
view.select({
field: "name",
match: [
"Rosencrantz",
"Guildenstern"
]
});
Alternative way to select the same objects using a filter:
view.select("(name='Rosencrantz')||(name='Guildenstern')");
KSViewport 7.4
The KSViewport class is used to open and inspect windows within KeyConfigure. Each KSViewport references a window, and a window could be referenced by multiple KSViewports. Newly opened windows are initially hidden and empty. They can be filled using the select() method, and displayed with the show() method.
KSViewport(String table)
KSViewport(String table, String title)
object
Creates a new KSViewport, opening a new window if necessary. The first style of the constructor creates a reference to the main KeyConfigure window for the specified table. The second style will open a new window unless there is already a window with the same title. If the window already exists, the new KSViewport object will refer to it.
view
KSView
The view of objects currently listed in the window.
getSelection()
KSView
Gets a new KSView object that contains the objects in the window's selection. This view will not change even if the selection changes within the window. To get the changed selection, call getSelection() again.
select(KSView view)
select(String filter)
boolean
Populate the window with a set of objects from the view's table. The first style of this method copies the contents of a KSView into the window. The second style accepts a String that is used as a filter to choose which objects to include in the window.
show()
boolean
Shows the window and makes it frontmost.
Ldap 7.4
The Ldap class is used to make queries to any LDAP server, including Active Directory. The class can only read (search) for information in the directory; it cannot insert, delete, or modify directory entries.
Ldap()
Ldap(String desc)
object
Creates a new Ldap object. The first style of this constructor will make the connection to the default server, if available. In the second style of the constructor the target server is provided in URI form. A URI starting “ldaps://” will create a connection using SSL, while a URI starting “ldap://” uses an insecure connection. The host name or IP address is provided, optionally followed by “:” and a non-standard port number
To connect to an LDAP server over a secure (SSL) connection:
var ld = new Ldap("ldaps://server.ad.sample.net");
bind()
bind(String creds)
bind(String dn, String password)
boolean
Bind the connection to a directory account. The first style of this method will attempt to use the default credentials of the logged in user account. For the second style the bind credentials are supplied as one string in the format “dn:password”. The last style takes the credentials as separate strings. Note that the dn must be fully qualified, for example “cn=Sam Pearson, cn=Users, dc=ad, dc=sample, dc=net”.
search(String basedn, function process)
search(String basedn, function process, function complete)
search(String basedn, object info)
boolean
Search for matches given a base DN, passing the results to a callback function. The first style of this method takes just the
basedn and
callback function that will be called for each match. The function will be passed two arguments: the entry's DN and an object with the entry's attributes. The second style of this method takes the
basedn and
callback function and also a
complete function that will be called when the query has finished. The
complete function is passed a numerical result indicating general success or failure. Both of these first two styles will search just for the given
basedn and gather all attributes of that entry if it exists. The third style of this method is passed the
basedn and an object that provides the
callback function, the
complete function, a
context that will become the functions'
this value, and various options to be used during processing.
info object
attributes
String or String[]
An array of attributes that should be gathered for each matching object. Set this property to null to gather all attributes (this is the default).
context
object
The callback (and complete) function's this value.
filter
String
Standard LDAP-formatted filter for matching objects within the search scope. A value of null (the default) matches all objects.
scope
String
The
scope of the search (default is “base”).
Value | Meaning |
“base” | search for object with the given basedn |
“one” | search for direct children of the given basedn |
“sub” | search for objects in the subtree rooted at the given basedn |
sizelimit
number
The maximum number of results that should be gathered in the search. A value of 0 (the default) specified no size limit.
timelimit
number
The maximum time, in seconds, that should be spent in the search. A value of 0 (the default) specified no time limit.
function callback(String dn, object entry)
number
The function that is called for each matching directory entry. It is passed the full DN of the matching entry and an object that contains properties corresponding to the attributes that were requested (in the attributes property above). Multi-valued attributes will be arrays in this object. Return a non-0 value to stop processing entries.
function complete(number status)
The function that is called once the search has finished.
To query for objects matching a simple filter:
ld.search("dc=ad, dc=sample, dc=net",
{
attributes: [ "cn" ],
filter: "(cn=Sam Pearson)",
scope: "sub",
callback: function (dn, entry) {
print("match: " + dn);
print(" cn: " + entry.cn);
}
});
Mail 7.4.1.2
The Mail class is used to send simple e-mail messages. Typically the message body would be read from a support file in the script bundle and then modified to include information specific to the particular message.
Mail(String host)
Mail(String host, number port)
object
Creates a new Mail object that will use the specified mail server. The first style of this constructor specifies the mail host, and will use the default mail port (25). The second style includes a custom port number in addition to the host name.
To connect to a mail server that supports open relaying:
var mail = new Mail("mail.sample.net");
mail.open();
error()
String or String[]
Returns the most recent results of a failed open() or send() call. The open and send methods return false on failure. Use the error method to retrieve the messages that the mail server sent.
To display the mail server's response to a failed operation:
var mail = new Mail("mail.sample.net");
if (!mail.open("somebody@sample.net", "s3cr3t")) {
var error = mail.error();
if (!error)
alert("connection failed");
else if (typeof error == "string")
alert(error);
else
alert(error.join("\n"));
}
open()
open(String user, String password)
open(String user, String password, number flags)
boolean
Initializes a connection to the mail server, optionally logging in with the credentials that are provided. If the server supports SSL, a secure connection will be established. If authentication is necessary, the server must support at least one of these mechanisms: PLAIN, LOGIN, CRAM-MD5, OAUTHBEARER. To use the OAUTHBEARER mechanisms an OAuth token must be obtained from the associated mail service. Depending on how your mail service issues tokens, it might be possible to use the XMLHttpRequest class to automate token retrieval. The details of this process are out of the scope of this document.
To connect to a mail server with a name and password:
var mail = new Mail("mail.sample.net");
mail.open("somebody@sample.net", "s3cr3t");
To connect to a mail server using a predetermined OAuth token:
var mail = new Mail("mail.sample.net");
mail.open("somebody@sample.net", "vF9dft4qmTc2...dGEuY29tCg==", 1);
send(String sender, String recipient, String message)
send(String sender, String[] recipients, String message)
send(String sender, String recipient, object message)
send(String sender, String[] recipients, object message)
boolean
Sends mail from the sender to the recipient(s). This method doesn't return until the mail has been sent, or a failure occurs. The
sender and
recipient values must be plain e-mail addresses with no common name component and no delimiting characters. For example, is correct, while is not a valid e-mail address (however, this latter format is typically used in the message envelope
From and
To headers).
message object
body
String
The body of the mail message. This value is required, although it can be set to the empty string. The message body is sent after all headers have been sent.
Subject
String
The mail message subject. Including a subject is recommended, since some spam filters might reject mail without a subject.
From
String
The name and address of the mail sender. This can be different from the actual sender, and typically includes the full name of the person sending the mail. If this value is omitted, the sender address will be used for the From header.
To
String
The names and addresses of the mail recipients. This can be different from the actual recipient list, for example when certain recipients are “blind copied”. If this value is omitted, there will be no To header in the message.
other
String
Any other value in this object will be treated as a header field, and added to the message envelope. Use such optional values with caution, since there are strict rules about the names, format, and contents of mail header fields.
To connect to a mail server as an authenticated user and send a simple message:
var mail = new Mail("mail.sample.net");
mail.open("somebody@sample.net", "s3cr3t");
mail.send(
"somebody@sample.net",
"jdoe@example.org",
{
Subject: "Some Topic",
From: "Some Body <somebody@sample.net>",
To: "John Doe <jdoe@example.org>",
body: "This is the body of the message."
});
Odbc 7.4
The Odbc class is used to access data through ODBC drivers and data sources installed and configured on the host computer. This class can also be used to access KeyServer's tables using SQL query syntax. Generally it is easier to use KSView and KSObject if the required information is available in that way.
Odbc()
Odbc(String desc)
Odbc(object parameters)
object
Creates a new Odbc object. The first style of this constructor will use the existing connection to the server, if available. This connection is always available to scripts running in KeyConfigure. In the second style of the constructor the login information is supplied as a connection string in the standard ODBC manner. The last style accepts the connection parameters as a JavaScript object and builds the connection string internally.
To connect to an ODBC data source and select some rows from a table:
var db = new Odbc("DSN=TheDataSource");
db.open({ labelled: true });
db.prepare("SELECT name,age FROM People WHERE department = 'Staff'");
db.execute(function (row) {
print(row.name + " is " + row.age + " years old");
});
db.close();
Alternative way to provide the connection information:
var db = new Odbc({
DSN: "TheDataSource"
});
close()
boolean
Close an open connection. Once the connection is closed no new queries can be made with the Odbc object until the connection is opened again. A new connection to the same data source can be created using the open() method.
execute(function process)
execute(function process, function complete)
execute(object info)
boolean
Execute the prepared query, passing the results to a callback function. The first style of this method takes just the
callback function that will be called for each result row. The function will be passed one argument, either an array with the requested columns or an object containing properties that correspond to the requested columns. The second style of this method takes the
callback function and also a
complete function that will be called when the query has finished. The
complete function is passed two arguments: a numerical result and an optional
String containing an error message. The third style of this method is passed an object that provides the
callback function, the
complete function, a
context that will become the functions'
this value, and various options to be used during processing.
info object
context
object
The callback (and complete) function's this value.
dateFormat
String
Format in which date values should be provided to the callback function. For possible values, see dateFormat description under the open method below.
labelled
boolean
If true, pass an object to the callback function with properties corresponding to the column names given in the query. If false, pass an array with just the values of the query columns.
function callback(object row, String[] columns)
boolean
The function that is called for each result row. Return true to stop processing rows.
function commence(String[] columns)
The function that is called once before row data is processed.
function complete(number status, String message)
The function that is called once the operation has finished.
Some SQL queries are not expected to return any results. In these cases it only makes sense to process the end result:
db.prepare("INSERT INTO People (name, age, department) VALUES ('Bilbo Baggins', 111, 'Acquisitions')");
db.execute({
complete: function (res, err) {
if (err)
print("error inserting row: " + err);
}
});
open()
open(object options)
boolean
Open a connection to the data source. The first style of this method opens the connection using default settings. The second style accepts an object that provides
options for the connection and for queries made on the connection. Multiple queries can be made on the same open connection. When the connection is no longer needed, use the
close() method.
options object
dateFormat
String
Format in which date values should be provided to the
callback function.
Value | Format |
“string” | a generic date string formatted according to OS and user settings |
“object” | a JavaScriot Date object |
“iso” | a string formatted according to the ISO-8601 standard |
“general” | a string formatted in as YYYYMMDDHHMMSS[GMTO] |
“seconds” | the number of seconds since 1970-01-01 |
“milliseconds” | the number of milliseconds since 1970-01-01 |
labelled
boolean
If true, pass an object to the callback function with properties corresponding to the column names given in the query. If false, pass an array with just the values of the query columns.
prepare(String query)
boolean
Prepare an SQL query to be submitted to the data source on the open connection. The SQL query uses standard syntax, and is processed according to the specific ODBC driver that is being used for the connection. Results of the query are processed by calling the execute() method.
Storage 7.4
The Storage class provides methods for accessing the data kept in storage objects. These objects are created by the host program when the script is loaded. For bundled scripts, any storage template files in the bundle's storage directory are added as objects to the global scope. The name of the object is derived from the file name. It will be the last component of the file name before the extension. So a storage template file named “sample.testStorage.json” will create a new storage object named “testStorage”. If there are multiple storage template files that would result in the same object name, only one will be used.
The HTML5 specification defines Storage objects to store only values that are strings. The implementation here supports any basic type, so you can store strings as well as numbers, boolean values, and even objects. Essentially, anything that can be represented as a JSON string can be stored.
It is not possible to construct new Storage objects other than through the file-based mechanism described above.
length
number
The number of items contained in this Storage object
clear()
Remove all items from this Storage object
getItem(String key)
object
Return the value of the item named key
key(number index)
String
Return the key at index
removeItem(String key)
Remove the item named key
setItem(String key, object value)
Set the item named key to value
XMLHttpRequest 7.4
The XMLHttpRequest class is a synchronous-only implementation of the widely used standard for sending requests and receiving responses from a web server. Because scripts will generally be synchronous in nature, and to simplify the usage of this functionality, the requests are made synchronously. This just means when you send a request, your script is paused while waiting for the response. It also means that setting up a request is easier, and there is no state to keep track of.
For scripting purposes here, the XMLHttpRequest class is convenient for accessing web APIs and other data-centric resources. Because these sources generally use JSON format for data transfer, this implementation will parse JSON content (as long as the response's “Content-Type” header is “application/json”) and will otherwise treat the response as plain text.
XMLHttpRequest()
object
Creates a new XMLHttpRequest object that can be used to make a request to an HTTP server.
readyState
number
The state of the request, with possible values listed here:
Value | State | Description |
0 | UNSENT | open() has not been called yet |
1 | OPENED | send() has been called |
2 | HEADERS RECEIVED | send() has been called, and headers and status are available |
3 | LOADING | Receiving; responseText holds partial data |
4 | DONE | The operation is complete |
response
object
The response to the request as an object, if the response content type is “application/json”, or null if the request was unsuccessful.
responseText
String
The response to the request as text, or null if the request was unsuccessful.
responseType
String
An enumerated value that defines the response type. It can have the following values:
Value | Data type of response property |
“json” | JavaScript object, parsed from a JSON string returned by the server |
“text” | a String containing the unparsed response |
status
number
The status of the response of the request. This is the HTTP result code (for example, status is 200 for a successful request).
statusText
String
The response string returned by the HTTP server. Unlike status, this includes the entire text of the response message (“200 OK”, for example).
timeout
number
The number of milliseconds to wait for a response before closing the connection. A value of 0 (the default) indicates there is no timeout.
getAllResponseHeaders()
String
Returns all the response headers, separated by CRLF, or null if no response has been received.
getResponseHeader(String header)
String
Returns the specified header, or null if the header doesn't exist in the response.
open(String method, String url, boolean async)
open(String method, String url, boolean async, String user)
open(String method, String url, boolean async, String user, String password)
Initializes a request to use the provided method for the given url. Since only synchronous requests are supported, async must be set to false. In the cases where user and/or password are provided, these strings will be encoded and sent in an “Authorization” header (using the Basic mechanism).
send()
send(String content)
Sends the request, with the content if provided. This method doesn't return until the response has arrived.
setRequestHeader(String header, String value)
Sets the value of an HTTP request header. You must call setRequestHeader after open, but before send. If this method is called several times with the same header, only the last value set will be used.
The app.progress object
The progress object provides a set of messages for controlling how progress feedback is displayed to the user. This is not a class that can be created, it is an object property of the global app object.
For an example of how the app.progress object is used, see Progress feedback pattern.
advance()
advance(number steps)
Advances the current progress context by the number of steps indicated. Calling advance() with no parameters is the same as calling advance(1). Calling advance(n) is the same as calling advance(1) n times.
close()
Closes the current progress context.
comment(String msg)
Sets the progress comment string to msg. This string is displayed in the Activity window alongside the progress bar.
open(number steps)
Opens a new progress context that will cover the given number of steps. This is an indication of how many times advance() will be called before the progress context ends with a call to close().
show()
Shows the Activity window without delaying.
The non-modal prompt object
Non-modal prompt objects are defined and returned from the main script. These objects do not have a class, but must contain certain properties that are used to create the prompt dialog and respond to user actions.
For an example of how to use the non-modal prompt object, see Non-modal user prompt pattern.
setup
object
An object describing the contents of the user prompt dialog. This object is identical in structure to the object passed to the modal
prompt() method.
setup object
fields
Array
The list of fields to display in the prompt dialog. Field types are described in
Prompt Field Types.
id
String
A unique value for use with unattended execution of the script. This should be a uniform type identifier in reverse DNS format using your organization's domain name. For bundled sripts it is recommended that the script id be use along with a suffix unique within the script (in case there are multiple prompts), for example, “org.domain.my-script.first-prompt”.
title
String
A string to be used for the prompt dialog's title.
version
number
The compatability version of this object, used by the host program to ensure consistent behavior. This documentation describes version 1 of the non-modal prompt object.
function cancel()
object or undefined
Called by the host program when the user clicks Cancel in the prompt dialog. This function can return nothing, indicating that the script has completed, or it can return another non-modal prompt object. Typically scripts will not implement a cancel function, allowing the script to end without further processing. Scripts that need to clean up or complete an operation after the prompt is cancelled should honor the user's intent to cancel the task and not return another prompt object, even though that is possible.
function proceed(object params)
object or undefined
Called by the host program when the user clicks OK in the prompt dialog. The function's single argument is an object containing the information provided by the user in the prompt dialog. This function can return nothing, indicating that the script has completed, or it can return another non-modal prompt object if further information is required. To avoid user frustration, scripts should not “chain” too many prompt dialogs in this manner.
Prompt Field Types
The modal and non-modal user prompt mechanisms require a list of fields that the user will be asked to enter. Prompt fields can each have one of several available types. The fields are listed in an array of objects whose properties define the behavior.
properties common to all input types
All fields have certain properties in common. These properies identify the field, specify its type, and provide a label, optional default value, and flag to tell whether the field is required.
id
String
The identifier to use when creating the result object. This string must be a valid JavaScript identifier name, and will be how the script code accesses the value within the resulting input object.
type
String
The type of the prompt field. See individual field types for the proper value to use.
label
String
The label to display in the user interface. This string is shown to the left of the input field. In many cases this label should have a “:” at the end, to conform with typical UI practices..
default
object
The value that this field has initially, when the prompt dialog is first displayed. The user will be able to change the field, but if not this value will be returned in the result object.
required
boolean or String
A flag indicating whether this field is required. If this property is true, the user must provide a value for the field. If no value is present and the user clicks OK, an alert will appear and the prompt dialog will not be dismissed.
String type (text)
A String field can be used to request any text, optionally limited to some max length or conforming to a pattern.
lines
number
The height of the input area in lines. If this value is omitted or set to 1 or less, the label will be to the left of the single-line input box. If the value is 2 or greater the label will be above the input box, which will extend from the left to the right of the prompt dialog.
max
number
The maximum length of the string.
pattern
String
A regular expression that the entered string must match. The required property for this field should be a string that shows the correct format. If the entered string does not match the pattern, an alert will be shown containing the required string.
Example of a String field:
{
id: "message",
type: "text",
label: "Enter the Message:",
default: "Hello, World!",
required: false
}
Number type (long)
A Number field accepts a whole number as input and optionally checks that the entered number is between the min and max values.
max
number
The maximum value for this field.
min
number
The minimum value for this field.
Example of a Number field:
{
id: "guess",
type: "long",
label: "Pick a number (1-10):",
min: 1,
max: 10,
required: true
}
Boolean type (bool)
A Boolean field shows a checkbox that can be checked (true) or unchecked (false).
Example of a Boolean field:
{
id: "save",
type: "bool",
label: "Save Changes",
default: true
}
Date type (date)
A Date field lets the user type a date and time, which is then parsed and returned as a Date object.
Example of a Date field:
{
id: "meeting_time",
type: "date",
label: "Meeting Time:",
required: true
}
Menu type (menu)
A Menu field shows a pop-up menu from which the user can choose one item. The possible choices are given in an array, and appear in the order listed.
options
Array
The list of options to put in the pop-up menu.
Example of a Menu field, where the value returned will be the 0-based index of the option that was chosen:
{
id: "scary",
type: "menu",
label: "Scariest Beast:",
options: [ "Lions", "Tigers", "Bears" ],
default: 1
}
Another example that returns specific values for each choice:
{
id: "flavor",
type: "menu",
label: "Flavor:",
options: [
{ label: "Vanilla", value: "fudge" },
{ label: "Chocolate", value: "city" },
{ label: "Strawberry", value: "fields" }
],
default: "fudge"
}
File type (file)
A File field is used to request that the user specify a file for input. Since the returned object is a KSFile, the requested file should be a text file with the information available on each line of the file.
Example of a File field:
{
id: "listfile",
type: "file",
label: "List of Names:",
required: true
}
Object type (aobj)
An object field can receive, via drag/drop or by searching by name, an object of the type given in the table property. The returned value will be a KSObject.
table
String
The table from which an object can be dragged.
Example of a Object field:
{
id: "policy",
type: "aobj",
label: "Policy:",
table: "policy",
required: true
}
Password type (pass)
A Password field is like a String field, but the input text is obscured in the prompt dialog.
max
number
The maximum length of the string.
Example of a Password field:
{
id: "passphrase",
type: "pass",
label: "Enter your Password:"
}
Hidden type (hide)
A hidden field will not be displayed in the prompt dialog, but will be added to the returned object. The label property is not needed for this type, but the default type should be present since it provides the value for the returned object.
Example of a Hidden field:
{
id: "secret",
type: "hide",
default: "hide this from view"
}
Note type (note)
A Note field is displayed in the prompt dialog, but has no associated value in the returned object. The id property is therefore unnecessary in this case.
Example of a Note field:
{
type: "note",
label: "Please fill in the items below"
}
Footnote type (foot)
A Footnote field is like a Note field, except that the text is displayed slightly smaller if possible.
Example of a Footnote field:
{
type: "foot",
label: "* Required"
}
Patterns
This section describes a few coding patterns that are typically used when writing scripts for extending KeyConfigure. There are many variations on the examples we'll give below, so they should be used to get an idea for how your scripts should work, and not strict, formal definitions for how they must work.
Main script closure pattern
The main script is loaded, parsed, and executed exactly as it is written. There are no separate entry points or “onXxxx” event handlers that need to be defined. However, the script should be contained within a simple closure that serves two purposes: it protects the global namespace from getting polluted with the script's variables, and it allows the script to return a value. Returning a value is necessary to implement non-modal user prompts.
The basic pattern looks like this:
(function () {
})();
One addition to this pattern is used when you return a value, for example when implementing a non-modal user prompt:
(function () {
return( ... );
})();
There are other common JavaScript tricks you can use. For example you could pass certain commonly accessed global objects into the function that provides the closure. This might provide a small performance boost for longer more complex scripts.
Non-modal user prompt pattern
Many scripts will need to request some information from the user before they can proceed with their task. The best way to accomplish this is to use a non-modal user prompt dialog, which does not block the user from accessing other windows within KeyConfigure.
To have KeyConfigure display a non-modal prompt dialog your script must return an objec that describes what the prompt dialog should look like and what information it should request. Here is the general idea:
(function () {
return({
version: 1,
setup: {
title: "Title For Dialog",
fields: [
{
id: "a_field",
...
},
{
id: "another_field",
...
}
]
},
proceed: function (params) {
}
});
})();
In this script we are returning a prompt object that tells KeyConfigure what to add to the prompt dialog, and what to do when the user fills out the requested information and clicks OK. Line 6 gives the object a version so KeyConfigure behavior will be the same for future releases. The setup.fields array on lines 9-20 lists the field descriptions in the order that they will be shown in the prompt dialog. See Prompt Field Types for information on the types of fields that can be used.
When the user click OK, KeyConfigure creates an object containing properties that match the id of each of the fields. This object is then passed to the proceed function defined by the script. In the sample code above we've defined two fields with ids ”a_field” (line 12) and ”another_field” (line 17). So the object passed to proceed will have properies with these same names, accessed like in the following code:
...
proceed: function (params) {
... params.a_field ...
... params.another_field ...
}
...
The type of each property depends on the type that was used when defining the corresponding field. Note that the name “params” is not special, and can be anything you want in your own scripts.
The proceed function is called only if the user clicks OK in the prompt dialog. If your script needs to know when the user clicks Cancel, provide a cancel function in the prompt object:
...
cancel: function () {
}
...
Although it is best to limit the number of separate times the user is prompted for a given task, it is possible to “chain” prompt dialogs by returning a prompt object from the proceed (or cancel) function.
Progress feedback pattern
For tasks that run longer than a few seconds, KeyConfigure will display an “Activity” window with a progress bar. For simple scripts, KeyConfigure can handle the progress bar without extra help. When a script calls an iterating method like forEach(), KeyConfigure can advance the progress bar as the iteration proceeds.
More complex scripts that call more than one iterating method or otherwise run through a loop can give KeyConfigure hints about the stages of progress as they are performed. For example, this partial script calls two iterating methods:
var list = [];
app.selection.forEach(function (obj) {
list.push(obj);
}
var viewport = new KSViewport("policy");
viewport.view.forEach(function (obj) {
list.push(obj);
}
If this script happens to run long enough that the Activity window is displayed, you would see the progress bar fill from left to right as the first forEach method ran, and then again from left to right as the second forEach method ran. We can help KeyConfigure show a more unified progress by telling it how many iterations will be run, and when each one completes. To do this we'll use the app.progress object.
app.progress.open(2);
var list = [];
app.selection.forEach(function (obj) {
list.push(obj);
}
app.progress.advance();
var viewport = new KSViewport("policy");
viewport.view.forEach(function (obj) {
list.push(obj);
}
app.progress.advance();
app.progress.close();
In this new script we've still got all the code from the previous version, and we've added some progress hints. On line 1 we tell KeyConfigure that there are two main stages to our task. Once the first iteration is complete, we tell KeyConfigure (line 6) that we've completed a stage. Then again when the second iteration is finished we tell KeyConfigure (line 12). Finally on line 13 we indicate that the two-stage process is complete. The basic pattern is to call app.progress.open() with the number of stages in our task, then call app.progress.advance() that many times, and lastly balance the open() with a call to app.progress.close().
Now we'll look at a script that calls two iterating methods and runs one for loop:
var list = [];
app.selection.forEach(function (obj) {
list.push(obj);
}
var viewport = new KSViewport("policy");
viewport.view.forEach(function (obj) {
list.push(obj);
}
for (var i = 0; i < list.length; i++) {
}
Since the for loop is within the script, KeyConfigure cannot handle the progress bar for that loop. We can use the app.progress object to move the progress bar during that loop, and integrate that with the overall progress of the three main stages of our task:
app.progress.open(3);
var list = [];
app.selection.forEach(function (obj) {
list.push(obj);
}
app.progress.advance();
var viewport = new KSViewport("policy");
viewport.view.forEach(function (obj) {
list.push(obj);
}
app.progress.advance();
app.progress.open(list.length);
for (var i = 0; i < list.length; i++) {
app.progress.advance();
}
app.progress.close();
app.progress.advance();
app.progress.close();
The first difference is that we've told KeyConfigure, via the app.progress.open() method on line 1, that there are three stages in our script. So that is a promise that we'll advance() three times (on lines 6, 12, and 21) before we close() (on line 22).
We'll take care of the for loop using the same basic methods: first we call app.progress.open() on line 14 indicating the number of times we are going to go through the loop (list.length times). Then, as we progress through the loop we call advance(), line 17, resulting in the proper number of calls promised to open(). Then on line 19 we balance out the open() with a close().
Keep in mind that handling the progress feedback is completely optional, and does not affect what your script can do. The only way it matters is in how well the progress bar reflects the actual progress of your script, and that only matters if your script takes longer than a few seconds. There are a few other methods available in the app.progress object, see app.progress object.
Bundles
Script bundles are folders that contain the main script file, a manifest file that provides some information about what the script does, storage template files used to create persistent storage objects for the script to use, and other supporting files.
Bundle structure
The bundle folder must have the extension “.jst”. The manifest file, contents detailed below, must be named “manifest.json”. The manifest provides the name of the main script (default “script.js”). Storage files are placed in a folder named “storage”, and a “support” folder contains resources that the script can load.
bundle-name.jst
manifest.json
script.js
storage
localStorage.json
support
somefile.txt
somedata.json
Bundles for scripts that do not need persistent storage or don't have extra resource files can leave out the corresponding folders. Storage template files have some restrictions on their names, as described in the localStorage section. Files in the support folder can be “.js”, “.json”, “.plist”, “.csv”, or other plain text files and can have any name that does not include the characters “:”, “/”, or “\”.
Working with Bundles
Sometimes it is easier to transfer a bundle as an archive instead of as a folder with separate files. For example, JavaScript bundles provided by Sassafras Software are typically archived in a ZIP-formated .jst file. If you want to create your own jst archives in a way that KeyConfigure (and ks-jst) accept, you can use any ZIP program. Make sure that the ZIP file you create does not contain the bundle folder itself, and only the contents of that bundle folder. It is also easy to create jst bundle archives using the ks-jst command-line tool.
For macOS users, BBEdit provides a convenient way to edit archived bundles. Open a compressed bundle in BBEdit to edit any file in the bundle, then save and BBEdit will add the changes to the file within the compressed bundle. Adding new files to the bundle requires that you recompress the bundle folder.
Manifest properties
The manifest contains a single JSON-formatted object with properties that describe aspects of the script. The simplest manifest file looks like this:
{
"id" : "org.domain.my-script",
"name" : "My Script"
}
The manifest can also provide an alternate name for the main script file, and a “target” property that describes what type of object the script can work with:
{
"id" : "org.domain.my-script",
"name" : "My Script",
"script" : "script.js",
"target" : {
"table" : "computer",
"required" : true,
}
}
properties of a manifest
id
String
The unique identifier for the script, which should be a uniform type identifier in reverse DNS format using your organization's domain name.
name
String
The label used by KeyConfigure for display in the user interface For scripts that prompt the user for information, it is common practice to end the name with an elipsis “...”.
script
String
The name of the main script file, defaults to “script.js”.
target
object
Describes what type of object the script can work with. By default, no target is expected by the script.
properties of target
table
String or String[]
The name(s) of the table(s) that can be provided to the script in the app.selection object.
required
boolean
Indicates whether there must be at least one object of the required type in the current selection in order to run this script (defaults to false).
multiple
boolean
Indicates whether there can be more than one object in the current selection when run this script (defaults to false).
ks-jst command-line tool
Scripts that do not require a selection of objects in order to run and do not need to open a viewport can be executed by a command-line tool named “ks-jst”. This tool is useful for running scripts on a schedule, or in other cases where the full user interface of KeyConfigure is not needed. There is basic support for user prompting and alerting. For scripts that are written to expect user input but must run unattended, there is a mechanism for providing the input via a JSON-formatted file.
The command line usage for ks-jst is:
ks-jst [options] [files...]
When a script runs in KeyConfigure it can share the authenticated connection that exists to the server. With ks-jst, if objects from the KeyServer are needed, the server's host must be given and an Administrator name and password must also be supplied. Bundled scripts can be run, and non-bundled scripts are also supported. You can even provide a sequence of JavaScript commands via the command line, and these will be executed in the order given.
Command line options
-e cmd
script command to load and execute (can be repeated)
-h host
server host or IP address (localhost)
-l level
logging output level of verbosity (0-7)
-n name
name of Administrator account
-o file
an alternate output file for the print method (default is stdout).
-p password
password of Administrator account
-s file
file to use for storage object (can be repeated)
-S folder
folder for working copies of storage objects
-u uri
server URI (format name:pass@host)
-z folder
create a bundle archive from the specified bundle folder. This option is used without any other options. A destination directory can be specified as well:
ks-jst -z org.domain.my-script.jst ~/Desktop
files...
After all options, the remaining arguments are scripts or script bundles. Each of these will be loaded, parsed, and executed in the order they are listed on the command line.
Differences from KeyConfigure
Most of the features that do not require KeyConfigure's user interface are supported by ks-jst. The main exceptions are:
- there is never an app.selection view defined
- the KSViewport class is not available
- the Object prompt field type is not supported
- if the script is not bundled, there will be no bundle object
- there is no progress indication, although the app.progress object will be present
Other differences in behavior are:
- the user prompts/alerts appear in the terminal session runnnig ks-jst, and are text-based
- the console object writes all output to stderr, with verbosity controlled by the -l option
- for persistent storage of objects based on a bundle's storage templates, the -S option must be used
Scripts should work unmodified from their KeyConfigure implementations unless they attempt to open a KSViewport. Scripts that use KSViewport will fail unless try/catch is used and the exception is caught.