Active Directory, PowerShell, VMware, vRA

External Validations with vRA 7.4 Custom Forms and vRealize Orchestrator with PowerShell

August 24, 2018

It took me almost all day to get the External Validations in vRA 7.4 Custom Forms to work properly and I figured I would share my experience in case it helps anyone else.

First you will need a Custom Form.. here is mine.

 

I will mostly be working with the Hostname and DNS Suffix fields.  One of those two “Text” fields up in the Top-Right will come into use later as it will be our argument feed into our PowerShell script.  More on that later.

Next you will need to create an “Orchestrator validation” in the custom forms.  You can give it any Validation Label you want that makes sense to you.

The Selection Action piece will provide Actions out of Orchestrator that have a return type of “string”.  This took me awhile to realize.  I’ll say that again.. Return type: HAS TO BE STRING

(Yes I know I spelled arguments wrong.. it took me all day to get this working I wasn’t worried about grammar.. I’ll fix it later).

Next, you will need to create an “Action” in vRealize Orchestrator.  I re-used code from the Invoke PowerShell Script Blueprint.  Below is the Action code that I am currently using (feel free to fix my spelling mistake – I’m keeping it consistent so it works).

var host = getHostByName(hostName);
var actionResult;
var arguements;

if(!host) {
	throw "Host '" + hostName + "' not found";
}

var session;
try {
	session = host.openSession();
	var script =  '& "' + script + '" ' + arguements;
	actionResult = System.getModule("com.vmware.library.powershell").invokeScript(host, script, session.getSessionId());
	var output = actionResult.getRootObject();
	System.log(output);
	if (output === 0){
		return ""
	} else {
		return "Hostname Already In Use"
		}
} finally {
	if (session){
		host.closeSession(session.getSessionId());
	}
}

function getHostByName(name) {
	if(!name) {
		throw "Host name not specified";
	}

	var hosts = Server.findAllForType("PowerShell:PowerShellHost");
	
	for each(host in hosts) {
		if(host.name == name) {
			return host;
		}
	}
}

Save this action somewhere in Orchestrator.. and you should now be able to find it in External Validations.

This particular action can be used for literally anything which is why I’m so happy I got this working… I’m essentially calling a PowerShell script to do all of my bidding.. that PowerShell script returns a 0 or 1.  With that result I can decide what I want to do.

So as you can see i have three fields I need to find inputs for.  The first one is very easy.. its simply the scripting server name which has to match Orchestrator’s PowerShell hostname.  If you haven’t loaded a PowerShell host you need to do that first.

The second one is the script that you want to run… this can be a constant as it is not going to change, put in the script (C:\…\…\…..name.ps1), I’m not using any quotes as I have no spaces in my filename.

The third one.. I’m having arguements with the way I spelled this.  You can see I am using one of those Text Fields that I put on the canvas.

Here is the secret sauce to that text field.  I’m literally putting in:
-fqdn <space>
Field of DNS Suffix (this is a dropdown they have to choose)
<space> -hostname <space>
Field of Hostname

Make sure you lock all of the fields down on your form so you require input!

You can see from the screenshot above this one that I’m highlighting the “Hostname” field if the script we run returns anything bad.

So… I guess the next thing you are going to want is the PowerShell script I’m actually running… eh?  (You will obviously need to change variables here)

Before I explain this script…. You need to know…The first thing about Infoblox integration… all records default to the DNS zone listed in the DHCP Options of the IPAM range.  You can change this post deployment.. but as designed you are stuck with whatever is listed in that DHCP DNS Suffix of the IPAM range.

So, this script is accepting Domain Suffix and Hostname from the Custom Form. 

I’m then importing the PowerShell Infoblox Module (https://github.com/rmbolger/Posh-IBWAPI)

I’m then setting a variable for what is hardcoded and set in the Infoblox appliance for the default domain suffix… and putting a variable together for current FQDN.. and what will be the FQDN after I fix it (post deployment).

I’m then setting credentials for Infoblox and ActiveDirectory connections.  If you need to know how to store passwords in secure format go here: https://www.pdq.com/blog/secure-password-with-powershell-encrypting-credentials-part-1/

I’m then setting the filters I want to search Infoblox with.. I want to make sure the hostname in the default DNS Suffix is clear… as well as the DNS Suffix I will be changing it to post depoyment.

Thirdly.. I want to make sure a Computer Object with the same name doesn’t already exist in AD.

If I pass all of those checks I’m passing a 0 back to Orchestrator… if any one of those fail I’m passing back a “1”.

param(
[Parameter(Mandatory=$true)][string]$fqdn,
[Parameter(Mandatory=$true)][string]$hostname
)

#Import-Modules
#################################################
Import-Module Posh-IBWAPI

#Current Information
##################################
$currentfqdn = "default.domain.com"
$currentHostname = $hostname + "." + $currentfqdn

#Set New Hostname
####################################
$newhostname = $hostname + "." + $fqdn

#Set Infoblox Credentials
####################################
$username = "infoblox_username"
$password = Get-Content "C:\Password.txt" | ConvertTo-SecureString

$creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $password

#Set AD Creds
####################################
$username = "Domain\ScriptingAccount"
$password = Get-Content "C:\AD_Password.txt" | ConvertTo-SecureString

$credsAD = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $password

#Set Infoblox Specific Information
####################################
$WAPIHost = "infoblox.domain.com"
$filter = "name:=$currentHostname"
$filter2 = "name:=$newhostname"

$temp = Get-IBObject -ObjectType record:host -filters "$filter" -Credential $creds -WAPIHost $WAPIHost -WAPIVersion 2.3 -IgnoreCertificateValidation

$temp2 = Get-IBObject -ObjectType record:host -filters "$filter2" -Credential $creds -WAPIHost $WAPIHost -WAPIVersion 2.3 -IgnoreCertificateValidation

$temp3 = Get-ADComputer -Credential $credsAD -LDAPFilter "(name=$hostname)" -SearchBase "DC=AD,dc=DOMAIN,dc=COM"

if ((!$temp) -and (!$temp2) -and (!$temp3))
{
    return 0 
} else {
    return 1
}

At this point I’ll refer you back to the Orchestrator code I posted earlier on:

if (output === 0){
		return ""
	} else {
		return "Hostname Already In Use"
		}

If output of the script is equal to zero… then return nothing.. essentially telling Custom Forms.. nothing to see here go ahead and continue the build… otherwise I want the highlighted Hostname field to say… “Hostname Already In Use”

I’m hoping to have a YouTube video up when I have time… hopefully this helps.. and feel free to @ me on Twitter.

You Might Also Like

1 Comment

  • Reply David Smith December 17, 2018 at 12:07 pm

    var host = getHostByName(hostName);
    did not work
    I ended up using
    var psHosts = Server.findAllForType(“PowerShell:PowerShellHost”); //returns array of psHosts
    var psHost = psHosts[0];

  • Leave a Reply