Executing operating system commands offers a wide range of options for getting information or perform activities fastly, effectively and with consolidated approaches. The caller must know exactly what he wants to do, otherwise damage can also be caused. VCF Automation provides the Command class for executing operating system commands. With the release 8.17.0 the class has been disabled for security reasons, but it was reintroduced with release 8.18.1 because of its widespread use. These class has some weaknesses that are eliminated by the present approach.
Execute Operating System Commands
The Advantage of this approach here are that ...
- in addition to standard output stream (stdout) the standard error stream (stderr) is also output.
- a timeout parameter exists so that the process is aborted when it exceeds.
- setting the system property com.vmware.js.allow-local-process is not necessary.
This advantages gives us a better opportunity to integrate calls of operating system commands into the JavaScript runtime environment.
You can download this source also from
my GitHub account.
/**
* @module de.stschnell
*
* @version 0.1.0
*
* @param {Any} in_command
* @param {number} in_timeOut
*
* @outputType Any
*
* @description Execute a command in the host operating system
*/
function executeCommand(command, timeOut) {
// Begin ---------------------------------------------------------------
/**
* Executes an operating system command.
*
* Hint: Command can be string or array of strings. If string value
* is provided command arguments are extracted by splitting the string
* using whitespace as separator.
*
* @function executeCommand
* @param {string|string[]} command - The command to execute.
* @param {number} timeOut - The maximum time to wait in milliseconds.
* @returns {Object}
*
* @example
* var command = [ "echo", "Hello World" ];
* var output =
* System.getModule("de.stschnell").executeCommand(command).output;
* System.log(output);
*
* @example
* // Delivers on Windows:
* // Microsoft Windows [Version 10.0.10586]
* var command = [ "cmd", "/c", "ver" ];
* System.log(executeCommand(command).output);
*
* @example
* // Delivers on VMware Aria Automation 8.12.0:
* // NAME="VMware Photon OS"
* // VERSION="3.0"
* // ...
* var command = [ "cat", "/etc/os-release" ];
* System.log(executeCommand(command).output);
*
* @example
* // Delivers on VMware Aria Automation:
* // Exit value: 2
* // ls: cannot access 'bambi': No such file or directory
* var command = [ "ls", "bambi" ];
* System.log(executeCommand(command).output);
*
* Set in the VMware Control Center the system property
* com.vmware.scripting.javascript.allow-native-object to true.
*
* Checked with Rhino 1.7.15, 1.7.14 and 1.7R4,
* with Bellsoft JDK 22.0.1, 21.0.1, 17.0.9 and 11.0.21,
* on Windows 10 and Ubuntu Linux 22.04.3 and
* with VMware Aria Automation 8.12.0, 8.14.1 and 8.16.2
*/
function _executeCommandNS(command, timeOut) {
if (
typeof command === "undefined" ||
command === null ||
arguments.length === 0
) {
throw new Error("command argument can not be undefined or null");
}
var _command;
if (Array.isArray(command)) {
_command = command;
} else if (typeof command === "string") {
_command = command.split(" ");
} else {
throw new Error("command argument must be string or array of string");
}
var _timeOut;
if (
typeof timeOut === "undefined" ||
timeOut === null ||
timeOut <= 1 ||
isNaN(timeOut)
) {
_timeOut = -1;
} else {
_timeOut = timeOut;
}
var output = "";
var exitValue = -1;
var bufferedProcessInputStream;
var bufferedProcessErrorStream;
try {
var process = java.lang.Runtime.getRuntime().exec(_command);
if (_timeOut === -1) {
process.waitFor(); // Infinity
} else {
process.waitFor(
java.lang.Long(_timeOut),
java.util.concurrent.TimeUnit.MILLISECONDS
);
}
exitValue = process.exitValue();
if (exitValue !== 0) {
System.error("Exit value: " + exitValue);
}
var processInputStream =
java.io.InputStreamReader(process.getInputStream());
bufferedProcessInputStream =
java.io.BufferedReader(processInputStream);
var processErrorStream =
java.io.InputStreamReader(process.getErrorStream());
bufferedProcessErrorStream =
java.io.BufferedReader(processErrorStream);
var line = "";
while ((line = bufferedProcessInputStream.readLine()) !== null) {
output += line + "\n";
}
while ((line = bufferedProcessErrorStream.readLine()) !== null) {
output += line + "\n";
}
} catch (exception) {
output += exception.message;
System.error(exception);
} finally {
if (bufferedProcessInputStream != null) {
bufferedProcessInputStream.close();
}
if (bufferedProcessErrorStream != null) {
bufferedProcessErrorStream.close();
}
}
return { "output": String(output), "exitValue": exitValue };
}
return _executeCommandNS(in_command, in_timeOut);
// End -----------------------------------------------------------------
}
|
The following image shows the difference between an incorrect call with executeCommand and the Command class. As can be clearly seen, an error message is returned with executeCommand, while no result is returned with the Command class. All we can see with the Command class is that the exit value is different from 0. A description of the reason, which is available, is not reported.
try {
var command = ["ls", "bambi"];
var output =
System.getModule("de.stschnell").executeCommand(command).output;
System.log(output);
var orchestratorVersion =
System.getModule("de.stschnell").getOrchestratorVersion();
// The command object is not available from release 8.17.0 until 8.18.0
if (System.compareVersionNumber(orchestratorVersion, "8.17.0") === -1) ||
(System.compareVersionNumber(orchestratorVersion, "8.18.0") === 1) {
var stdCommand = new Command(command);
stdCommand.execute(true);
var stdResult = stdCommand.result;
if (stdResult !== 0) {
System.error("Exit value: " + stdResult);
}
var stdOutput = stdCommand.output;
System.log(stdOutput);
}
} catch (exception) {
System.error(exception);
}
|
Conclusion
With the approach presented here, operating system commands can be executed like with the VCF Automation Standard, which is not available from release 8.17.0 until 8.18.0. The additional options with the stderr output and a time-out parameter offer us significantly better options to handle calls of operating system commands.