vRO – Convert CSV String Input to Multidimensional Array


I’ve been playing around with workflow scripts and one thing popped in my mind that might be useful in future was to parse a CSV from 3rd party source into vRO workflow and utilise it. Created a simple CSV file, parsed to vRO and I realised that it becomes a pure string.

In this blog post, I will be attaching and a script that converts CSV string input into multidimensional array and in the end, I will be going through some of the use cases.


In this example, what I will be presenting is:
  1. Use SSH workflow to get a CSV file from remote linux server and parse the CSV file as an attribute
  2. Pass above attribute to a scriptable task, convert it to a multidimensional array
  3. Utilise it

Let’s get started!

1. First of all, create a workflow, I called it “Convert CSV String Input to Hash Table”.

2. Edit the workflow, navigate to General tab and create attributes as per below. It may differ based on how you want to parse a CSV file from external source. In this case, I used a cat command to simply output a CSV file.


3. Go to Schema, put a scriptable task and call it “Convert”


4. Go to Script tab and put the following script in. Ensure attrCsvInput is recognised, it will be highlighted as pink.

var output = new Object();
var numberOfColumns = attrCsvInput.split('\n')[0].split(',').length;
var numberOfRows = attrCsvInput.split('\n').length - 1;
var tempArray = new Array();

for (i = 0; i > numberOfColumns; i++) {
    for (j = 1; j > numberOfRows; j++) {
    output[attrCsvInput.split('\n')[0].split(',')[i]] = tempArray;
    tempArray = new Array();
for (var k in output) {
    System.log('key is: ' + k + ', value is: ' + output[k]);

5. Finish off the visual binding as per below.


6. Let’s setup a SSH connection to a remote linux box. Search for the SSH workflow and put it between start and Convert scriptable task.


7. Finish off the binding as per below and make sure unused inputs are set to NULL, i.e. path, passphrase and encoding to NULL.






8. Run the workflow and you will see that the CSV file is converted to a multidimensional array, 3 keys Name, Age and Sex and values accordingly.


Use Cases

Replace the following bit in the end of the scriptable task to one below.


for (var k in output) {
    System.log('key is: ' + k + ', value is: ' + output[k]);


System.log("People younger than 30 are: ");
for (var o = 0; o < output["Age"].length; o++) {
    if (output["Age"][o] < 30) {
        System.log(output["Name"][o] + ": " + output["Age"][o]);
Run the workflow. An example output attached below and as shown, people younger than 30 years old are listed.

Further, you could filter it by either man or woman…etc.

One of the recommendations is to create this parsing function as an action, input to be a CSV input and output to be a JavaScript array.

Hope this helped for who requires external parsing CSV input to a vRO workflow and as always, feel free to leave a commend for any clarifications or questions 😀


vRO Deepdive Series Part 4 – Log Handling, Exception Handling and Failing Back


Continuing the vRO deep dive series and this is the 4th part. This will be discussing log handling, exception handling and failing back.

Feel free to revisit the previous deep dive series:

Log Handling

vRO provides 3 types of log handling:

  • Log
  • Warning
  • Error

Let’s do some exercise and see the difference between them.

First of all, create a workflow calling it what you would like to (I called it “hi”) and navigate to the Log tab under Schema. You will find 7 default loggings:

Screenshot 2015-06-16 09.44.53

For the starters, let’s try System log out. Drag and drop the element in like the following:

Screenshot 2015-06-16 09.45.39

Edit the System log and navigate to Scripting. You will find an auto-generated script “System.log(text);”.

Screenshot 2015-06-16 09.45.53

Let’s take a look at System warning and error as well, drag and drop others like the following screenshot:

Screenshot 2015-06-16 09.48.46

Edit the System warning and it will show you a similar script as System log, “System.warn(text);”

Screenshot 2015-06-16 09.46.43

Pretty much identical for System error, “System.error(text);”

Screenshot 2015-06-16 09.46.56

Let’s run the workflow and see how they look differ on the vRO logging tab. Create an attribute called attrText and the value to be “Different types of logging”.

Screenshot 2015-06-16 09.47.31

For each element, finish up the visual binding like the following:

Screenshot 2015-06-16 09.47.54

Time to run the workflow. Execute and it will present 3 different types of logging:

  • Log in a normal font
  • Warning in bold
  • Error in red and bold

Screenshot 2015-06-16 09.49.09

One thing I would like to highlight before moving on is that you do not need to use the above element in order to do logging. Within a scriptable task, you could always use System.log(text), System.warn(text) or System.error(text). Will go a bit deeper into this shortly.

Time for a proper exercise! For the next, I will be going through creating a network adapter on a virtual machine with different types of network adapters.

First of all, remove all 3 logging elements made previously and drag and drop a scriptable task. Navigate to the Scripting tab and paste the following script in:

System.log("Adding a virtual NIC to this VM with portgroup: " + Portgroup.name);
// Create connectable info for network
var connectInfo = new VcVirtualDeviceConnectInfo();
connectInfo.connected = true;
connectInfo.startConnected = true;
connectInfo.allowGuestControl = false;
// Create Network BackingInfo
var netBackingInfo = new VcVirtualEthernetCardDistributedVirtualPortBackingInfo();
netBackingInfo.port = new VcDistributedVirtualSwitchPortConnection();
netBackingInfo.port.switchUuid = Portgroup.config.distributedVirtualSwitch.uuid;
netBackingInfo.port.portgroupKey = Portgroup.key;
// Create VirtualNetwork
if (Type.toUpperCase() === "VMXNET3") {
vNetwork = new VcVirtualVmxnet3();
} else if(Type.toUpperCase() === "E1000E") {
vNetwork = new VcVirtualE1000e();
vNetwork.backing = netBackingInfo;
vNetwork.addressType = "Generated";
vNetwork.connectable = connectInfo;
// Create Network ConfigSpec
var deviceConfigSpec = new VcVirtualDeviceConfigSpec();
deviceConfigSpec.device = vNetwork;
deviceConfigSpec.operation = VcVirtualDeviceConfigSpecOperation.add;
var configSpec = new VcVirtualMachineConfigSpec();
var configSpecArray = new Array(); 
configSpec.deviceChange = configSpecArray;
// Run the task
Task = VM.reconfigVM_Task(configSpec);

Once the script is in place, create three inputs as per the following screenshot:

Screenshot 2015-06-16 11.04.08

As depicted above, the workflow will require 3 inputs from the end users; virtual machine, portgroup and type. For the type, instead of asking the end user to manually type the input in, it would be better to pre-define a list and let them select one. This would make it easier for both workflow developers and users.

Go back to the General tab, change the type of the attribute attrTypeList to Array of string and add VMXNET3 and E1000E:

Screenshot 2015-06-16 11.04.31

Screenshot 2015-06-16 11.04.26

Once done, go to Presentation tab, select Type, choose “Predefined list of elements” and link it to pre created attribute attrTypeList.

Screenshot 2015-06-16 11.05.04

Screenshot 2015-06-16 11.05.14


Lastly, finish off the Visual Binding:

Screenshot 2015-06-16 11.05.47

All done! Let’s run the workflow to ensure it does the job. For the next example, I will be choosing a portgroup with VLAN1153 and VMXNET3 network adapter.

Screenshot 2015-06-16 11.18.10

Submit the request. Once the workflow completes, see if VMXNET 3 network adapter with portgroup VLAN1153 has added:

Screenshot 2015-06-16 11.19.01

Let’s create another one with VLAN1153 in E1000E type. Submit another request:

Screenshot 2015-06-16 11.19.50

Now we are confident that the workflow creates a portgroup as intended, it’s time to go through the logging. What I will be showing shortly is:

  • Selecting VMXNET3 = informational message will be logged
  • Selecting E1000E = warning message will be logged

Go back to the scriptable task and modify like the following:


// Create VirtualNetwork
    if (Type.toUpperCase() === "VMXNET3") {
    vNetwork = new VcVirtualVmxnet3();
} else if(Type.toUpperCase() === "E1000E") {
    vNetwork = new VcVirtualE1000e();


// Create VirtualNetwork
if (Type.toUpperCase() === "VMXNET3") {
    vNetwork = new VcVirtualVmxnet3();
    System.log("VMXNET3 Virtual Adapter will be created");
} else if(Type.toUpperCase() === "E1000E") {
    vNetwork = new VcVirtualE1000e();
    System.warn("VMXNET3 is recommended, but E1000E will be created");

Have a look at the example runs below:

  • 1 x VLAN997 VMXNET3 portgroup

Screenshot 2015-06-16 11.26.38

  • 1 x VLAN997 E100E portgroup

Screenshot 2015-06-16 11.28.08

This is how informational or warning message could be used. For the error message, it will be discussed in the next topic “Exception Handling”.

Exception Handling

An exception handling in the programming world is defined as

Exception handling is the process of responding to the occurrence, during computation, of exceptions – anomalous or exceptional conditions requiring special processing – often changing the normal flow of program execution

Why would you need to do exception handling? The reason is simple, when something never expected happens, information of the exception has to be handled, e.g. error message logged, locate where it happened…etc, which will allow easier troubleshooting for the developers.

The best way to catch an exception is to use try & catch:

try {
    ...... script
} catch (e) {

Whatever fails in try statement, the error message will be saved to the variable e and then logged as an error message.

Will be continuing with the example used in the previous section. Edit the scriptable task and replace the whole lines with the following script:


try {
    System.log("Adding a virtual NIC to this VM with portgroup: " + Portgroup.name);
    // Create connectable info for network
    var connectInfo = new VcVirtualDeviceConnectInfo();
    connectInfo.connected = true;
    connectInfo.startConnected = true;
    connectInfo.allowGuestControl = false;

    // Create Network BackingInfo
    var netBackingInfo = new VcVirtualEthernetCardDistributedVirtualPortBackingInfo();
    netBackingInfo.port = new VcDistributedVirtualSwitchPortConnection();
    netBackingInfo.port.switchUuid = Portgroup.config.distributedVirtualSwitch.uuid;
    netBackingInfo.port.portgroupKey = Portgroup.key;

    // Create VirtualNetwork
    if (Type.toUpperCase() === "VMXNET3") {
        vNetwork = new VcVirtualVmxnet3();
        System.log("VMXNET3 Virtual Adapter will be created");
    } else if(Type.toUpperCase() === "E1000E") {
        vNetwork = new VcVirtualE1000e();
        System.warn("VMXNET3 is recommended, but E1000E will be created");

    vNetwork.backing = netBackingInfo;
    vNetwork.addressType = "Generated";
    vNetwork.connectable = connectInfo;
    // Create Network ConfigSpec
    var deviceConfigSpec = new VcVirtualDeviceConfigSpec();
    deviceConfigSpec.device = vNetwork;
    deviceConfigSpec.operation = VcVirtualDeviceConfigSpecOperation.add;
    var configSpec = new VcVirtualMachineConfigSpec();
    var configSpecArray = new Array();
    configSpec.deviceChange = configSpecArray;
    // Run the task
    Task = VM.reconfigVM_Task(configSpec);
} catch (e) {

Causing an exception with this workflow is quite simple, just pick a portgroup that the virtual machine doesn’t have access to. In this example, VLAN23 was chosen:

Screenshot 2015-06-16 11.50.40

Since VLAN23 portgroup doesn’t exist, it now presents an error message saying “vNetwork is not defined”. One odd thing here is that looking at history of the workflow, it says the workflow was successful. Why is this? It’s because the exception was caught but wasn’t thrown properly, i.e. the workflow was not terminated. The way of throwing an exception is using “throw” statement. Add the throw statement like the following:


} catch (e) {
} catch (errorCode) {
    throw errorCode;

Once the change is made, the error will be thrown when an exception happens. One thing to consider is, where will it be thrown to? The exception must be handled once it is thrown.

Go back to the Schema and under the Generic tab, you will be able to find “Throw Exception” element.

Screenshot 2015-06-16 11.51.06

Throw exception element could be treated as End workflow but the difference is, the workflow was successful or failed.

Drag and drop the Throw exception element on the Scriptable task and a dotted red arrow will be created.

Screenshot 2015-06-16 11.51.21

Doing this will automatically create an attribute called errorCode. The purpose of this attribute is to catch any exception was thrown and forward it to the Throw exception element. This is why the variable e has been modified to errorCode earlier.

Saving the workflow will cause an error saying “Exception binding was not set”. This is because the workflow expects the scriptable task to bind the error message as an attribute. Edit the scriptable task, navigate to Exception and bind it to errorCode:

Screenshot 2015-06-16 11.51.30

Also, do the visual binding like below:

Screenshot 2015-06-16 11.52.05

Let’s run the workflow again choosing VLAN23. Unlike the previous example, now it will end in the throw exception state (the Throw exception element is highlighted).

Screenshot 2015-06-16 11.53.30

This is how you handle exceptions and will be moving onto fail-back process.


In my opinion, fail-back is one of the important aspects when developing a workflow. Continuing with the example above, let’s say there are 3 more tasks after creating a network adapter which I will be calling X, Y and Z and if task Y fails, what would you do to the network adapter created in the previous stage? The answer is obvious, it has to be removed, you don’t want the users to run the workflow multiple times ending up with 10 identical network adapters on a single virtual machine.

Let’s implement a simple fail-back process in this workflow. First of all, create an attribute called attrDevice with type to be Any (well there is no type with VC:VirtualDevice). This will be used to keep the device information.

Screenshot 2015-06-16 13.39.04

Once done, drag and drop 3 scriptable tasks between Create Network Adapter scriptable task and End element and call them Task X, Task Y and Task Z accordingly. Make sure you bind errorCode as the exception variable across 3 scriptable tasks and also, hover over and drag red arrow to Throw element.

Screenshot 2015-06-16 13.42.03


Screenshot 2015-06-16 13.42.11

Screenshot 2015-06-16 13.41.20

When task X,Y or Z fails, we want to delete the network adapter created. To do this, simply drag and drop a scriptable task between Task X and the Throw element and call it Remove Network Adapter:

Screenshot 2015-06-16 13.43.54

The problem in the above screenshot is that when the Task Y fails, it will just throw an exception without failing back. It will go directly to the Throw exception element. To correct it, click on the red line between the task Y and the Throw exception element, press delete and re-join it to Remove Network Adapter task. Repeat it to Task Z and the final state will look like the following:

Screenshot 2015-06-16 13.45.08

Paste the following script into Remove Network Adapter scriptable task:

try {
    System.error("An error has occurred, removing the created network adapter: " + attrDevice);

    var deviceConfigSpec = new VcVirtualDeviceConfigSpec();
    deviceConfigSpec.device = attrDevice;
    deviceConfigSpec.operation = VcVirtualDeviceConfigSpecOperation.remove;

    var configSpec = new VcVirtualMachineConfigSpec();

    var configSpecArray = new Array();

    configSpec.deviceChange = configSpecArray;

    Task = VM.reconfigVM_Task(configSpec);
} catch (e) {
    errorCode = e;
    throw errorCode;

And also, finish off the Visual Binding:


Screenshot 2015-06-16 13.46.54


Screenshot 2015-06-16 13.47.34

All done, let’s run and see the fail-back works. The following depicts the virtual machine has two network adapters, VLAN444 and VLAN1153:

Screenshot 2015-06-16 15.17.26

Let’s intentionally throw an exception in Task Y. Do the Visual Binding for errorCode and type the following in the scripting field:

errorCode = "This is intentional";
throw errorCode;

Let’s run it!

Screenshot 2015-06-16 15.20.41

It has thrown an exception at the Task Y and looking at how many network adapters the virtual machine has, you will see that the network adapter wasn’t created. Fail-back was successful!

Screenshot 2015-06-16 15.21.50


Hope this blog post was helpful and as always, feel free to contact me for any clarifications or help.

The next series will cover “Introduction to Relationship Between vRO & vRA” which is a big topic, stay tuned! 😀

vRA – Get Reservation Policy ID from vRO


I’ve been dealing with Reservations & Reservation Policies on vRA and found out that instead of using a SQL query, it was able to use vRO to pull Reservation Policy ID information out. In this blog post, I will go through both ways and explain the difference.

If you aren’t familiar with Reservation Policy ID, read the excellent blog by Kushmaro.

SQL Query

The following is the SQL query you could use in order to pull Reservation Policy ID out:

SELECT [id],[name] FROM [vCAC].[dbo].[HostReservationPolicy]

Login to SQL Management Studio and run the query above. If you don’t have access, ask database administrator to run it and get the output for you.

The attached screenshot below is a sample output:


It was quite easy, wasn’t it? Let’s take a look at vRO query.

vRO Query

It’s fairly simple to use vRO to query Reservation Policy ID. First of all, create a workflow and attach two attributes as the following:


For Reservation values, expand Reservations folder and add Reservations you would like to:


For vCACHost, select the vRA server.

Now, click on the Schema tab and drag and drop a scriptable task between start and end:


Edit the scriptable task and finish the Visual Binding like the below:


Navigate to Scripting tab and paste the script:

for each (var r in Reservation) {
  var reservationPolicyId = r.getEntity().getLink(vCACHost, "HostReservationPolicy");
  for each (var p in reservationPolicyId) {
    System.log("Reservation Policy Name is: ");
    System.log("Reservation Policy ID is: ");

Run the workflow and a sample output is shown below:


Comparing both outputs from SQL and vRO, it seems different. There are 5 Reservation Policies from SQL whereas 3 from vRO. Why is this?


Let us first take a look at how many Reservation & Reservation Policies are there in the vRA environment I am connected to:



Even though there are 5 Reservation Policies, it does not mean that Reservations use all of them. In this case there are 3 Reservations and they are using only 2 Reservation Policies.

In summary, if you do a SQL query, it will show you Reservation Policy IDs across all Reservation Policies whereas vRO will only return you the ones being used by Reservations.

Hope this was useful and feel free to leave a comment for any clarifications.