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. VMware Aria Automation provides the Command class for executing operating system commands. But these has some weaknesses that are eliminated by the present approach.

Execute Operating System Commands

The Advantage of this approach here are that ... 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} command
 * @param {number} timeOut
 *
 * @outputType Any
 *
 * @example
 * var command = [ "echo", "Hello World" ];
 * var output = System.getModule("de.stschnell").executeCommand(command).output;
 * System.log(output);
 */

/**
 * Set in the VMware Control Center the system property
 * com.vmware.scripting.javascript.allow-native-object to true.
 *
 * Checked with Rhino 1.7.14 and 1.7R4,
 * with Bellsoft JDK 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 and 8.14.1.
 */

/**
 * 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
 * // 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);
 */
function executeCommand(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 };

}

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.

vmware aria automation comparison of the call of an operating system command with expected error message in stderr with executecommand and with the command class - action perspective
try {

  var command = ["ls", "bambi"];

  var output = System.getModule("de.stschnell").executeCommand(command).output;
  System.log(output);

  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 VMware Aria Automation Standard. The additional options with the stderr output and a time-out parameter offer us significantly better options to handle calls of operating system commands.



This site is part of blog.stschnell.de