TL;DR
Some Powershell functions that can be used to invoke a REST API call, with a json payload, against a vRO workflow with parameters.

Introduction

As part of a fairly complex piece of server automation work being completed, there was a requirement to be able to call a workflow that I’d created within the vRO. The particular workflow in question was one that used the vRO Puppet plugin to classify a Linux based node, CentOS in this example, and remediate.

This workflow is to be called after the VM has been built to spec and has been registered within DNS. (Further article to follow on how I register DNS records via Powershell)

The majority of the server automation is driven from a Powershell module that gets called via the vRA (vRealize Automation Center) from an Advanced Services blueprint.

The article, How to use PowerShell to start an Orchestrator Workflow gave me the majority of what I needed to get started, but I wanted to use the Powershell ‘Invoke-RestMethod’ to do the grunt work instead of Invoke-WebRequest as it seemed more elegant.

Objective

  • To execute a vRO workflow via the REST API, with parameters, from a Powershell function.
  • vRO workflow has a number of parameters that have to be passed to it to execute correctly.

Infrastructure setup in this example

  • vRealize Orchestrator is embedded within the vRealize Automation appliance.
  • The Powershell module (that contains the functions) exists on the registered Powershell host.
  • The Powershell host used to initiate Powershell scripts is the vRealize IaaS server (added as a Powershell host).

Assumptions

  • The Powershell version used here is v3.0 running on Windows 2012 R2 Server.
  • The functions assume that a vCenter connection has already been established with the appropriate rights.
  • The following functions exist within a Powershell module files (.psm1) to be called as and when.
  • The functions do not have appropriate error handling.

The vRO workflow

The vRO workflow in this example is expecting the following parameters;

className 	= The classname you want to inject into the <nodename.pp> file
masterName 	= The Puppet master server
environment	= The environment that the Puppet master is going to use. i.e., dev, prod etc
vmMoRefID	= The VM Managed Object Reference ID, for example 'vm-246870'  

The Powershell Code

The LogWrite function call you will see below is a function I use to create my log files. I haven’t supplied that function here, so you can just comment it out.

Function ExecutevROWorkflow - executes a vRO workflow

	<#
		.SYNOPSIS Executes a vRO workflow by ID

		.Description

		Parameters
		$vroUserName		= vRO Username
		$vroUserPassword	= vRO password
		$strWorkflowID		= The unique ID of the workflow to execute (can be found in design mode on vRO)
		$vroJsonPayload		= Path to correctly formatted vRO payload file in .json format
			- This payload comes from another function.

	#>
	Function ExecutevROWorkflow($vroUserName, $vroUserPassword, $vroWorkflowID, $vroJsonPayload) {

	$strvCOUrl = "https://<VRO_URL>:8281/vco/api/workflows/$($vroWorkflowID)/executions"
	$strUserName = $vroUserName
	$strUserPassword = $vroUserPassword
	$strJsonBody = $vroJsonPayload
	$strContentType = "application/json"

	# To allow a connection to the vRO
	add-type @"
		using System.Net;
		using System.Security.Cryptography.X509Certificates;
		public class TrustAllCertsPolicy : ICertificatePolicy {
			public bool CheckValidationResult(
				ServicePoint srvPoint, X509Certificate certificate,
				WebRequest request, int certificateProblem) {
				return true;
			}
		}
	"@
	 [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

	# Setting up credentials for use in the initial auth header request
	$strAuth = $strUserName + ':' + $strUserPassword
	$encodedPassword = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($strAuth))

	# It's header and body time
	$objHeaders = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
	$objHeaders.Add("Authorization", "Basic $($encodedPassword)")

		Try {
			LogWrite "Invoking vRO workflow ID: $($vroWorkflowID)"
			$objResponse = Invoke-RestMethod -Method Post -uri $strvCOUrl -Headers $objHeaders -Body $strJsonBody -ContentType $strContentType -ErrorAction Stop
			LogWrite "vRO workflow ($($vroWorkflowID)) was invoked successfully"
		}
		Catch {
			LogWrite "vRO workflow ($($vroWorkflowID)) was not invoked"
		}
	}
    

Function GenerateJsonForPuppetWorkflow - creates a correctly formatted json string to be used with the REST API call in the above function

	<#
	.SYNOPSIS Generates required json formatted payload for invocation against the vRO API
	
	.Description

	Parameters
	$strVMName		= VM Name
	$strClassName	= Classname that you want injecting into the node definition ,<vmName>.pp on your Puppet master
	$strMasterName	= Puppet master
	$strEnvironment	= Puppet master environment. (dev, prod, ua etc)

	#>

	Function GenerateJsonForPuppetWorkflow($strVMName, $strClassName, $strMasterName, $strEnvironment) {
	
	$strVMMoRefID = GetMoRefFromVMName $strVMName

	# Prepare the Json formatted string
	$strJsonBody = "{""parameters"":[{""type"":""string"",""scope"":""local"",""name"":""className"",""value"":{""string"":{""value"":""$($strClassName)""}}},`
	{""type"":""string"",""scope"":""local"",""name"":""masterName"",""value"":{""string"":{""value"":""$($strMasterName)""}}},`
	{""type"":""string"",""scope"":""local"",""name"":""environment"",""value"":{""string"":{""value"":""$($strEnvironment)""}}},`
	{""type"":""string"",""scope"":""local"",""name"":""vmMoRefID"",""value"":{""string"":{""value"":""$($strVMMoRefID)""}}}]}"

	return $strJsonBody

	}
	

Function GetMoRefFromVMName - returns the MoRefID of a virtual machine from a currently established vCenter connection This is used to identify the VC:Virtualmachine object of the VM as a required input to the vRO workflow that runs later.

  
	<#
	.SYNOPSIS Returns the VM's unique vCenter MoRefID (Machine Object Reference ID). This is used to identify the VC:Virtualmachine
			  object of the VM as a required input to the vRO workflow that runs later.
	#>
	Function GetMoRefFromVMName($strVMName) {

	$vmMoRef = Get-VM | select name,id | where {$_.name -EQ $strVMName}
	[string]$strVMMoRefID = $vmMoRef.Id
	$strVMMoRefID = $strVMMoRefID.Replace("VirtualMachine-","")
	return $strVMMoRefID
	}  
	

If you have any questions, comments or praise/criticsm please drop it into the comments thread below.

Useful Links

The excellent vCO Team blog
How to use PowerShell to start an Orchestrator Workflow
How to use the REST API to Start a Workflow

Highly useful Chrome extension for testing out REST requests/responses
Chrome Advanced REST Client Extension

Powershell KBs
‘Invoke-RestMethod’