Categories
Aria Automation VMware

Aria Automation custom form Active Directory OU lookup

I recently ran into a fun challenge while working on an Aria Automation (formerly vRealize Automation) Windows Server build automation project. I needed to dynamically build a dropdown menu of Active Directory organizational units (OUs) for a user to select where the server’s computer object would reside once provisioned.

To make this more challenging, I didn’t have much experience with JavaScript and I had zero experience with Aria Automation Orchestrator Actions. So, I felt this was the perfect time to test ChatGPT and how I could potentially use it to learn and enhance my productivity. Lastly, kudos to Dale Hassinger over at vcrocs.info for helping me get reacclimated with Aria Automation.

I will be providing screenshots of the process but will be blurring data for security purposes. Additionally, this was developed on version 8.10.

The end result

Riveting stuff – but seriously, when using a combobox for this purpose, the user has the option to click and scroll through an alphabetized list of OUs or searching by typing. This is an exceptional user experience, even with hundreds of OUs to sort through.Ultimately, this seemingly simple field will enable the user to quickly enter consistent data that can later be used to further automate build processes.

The process

Piecing together how this even works could be mind-trip for the uninitiated – it was for me. In short:

  1. Upon loading, a custom form field calls out an Aria Automation Orchestrator (vRO – old habits die hard) action, asking for a list of OUs for the user to choose from
  2. vRO Action binds to and asks Active Directory for a list of OUs
  3. Active Directory returns the list to vRO
  4. vRO Action receives the list, formats it to our liking, and returns it to the form where our user is presented with a list

Setting it up

The first step is to add the Active Directory domain to the Aria Automation Orchestrator Inventory.

Navigate to Library, Workflows, then search for “Add an Active Directory Server,” and click Run.

This gives the Orchestrator native Active Directory plugin library access to your Active Directory domain. Note: You will need a service account to bind to Active Directory.

Going through the workflow wizard is outside of the scope of this post, but it’s straightforward. Here’s VMware documentation on using the Active Directory plugin for more details.

Once added, you can verify connectivity by navigating to Administration, Inventory, scroll through the tree to Active Directory, and expand the node. You should see your domain listed and you will be able to drill down through your Active Directory OU structure.

Next, we’ll need to create a set of Orchestrator actions to query Active Directory for a list of OUs.

Navigate to Libray, Actions, then click New Action. Give the action a relevant name, i.e. getServerAdOuList. Provide a Module name, i.e. com.organization.ad, a Description, and tags.

Move over to the Script tab.

As an aside – this is when I tapped ChatGPT on the shoulder to help me in areas where I was unfamiliar. I still had to guide the process and know what was going on, but it shaped up to be an invaluable peer programmer of sorts. I easily saved several days and learned a lot – it’s very proficient at explaining code.

Here’s the JavaScript to use:

// AD domain name
var adName = "example.com";
// Search base/root OU where server computer objects are
var ldapDn = "OU=Servers,OU=example,DC=com";

// Configure attributes that need returned from AD
var ATTRIBS = ['distinguishedName', 'canonicalName'];

// Get AD Host object from AD plugin library
var adHosts = AD_HostManager.findAllHosts();
var host = adHosts[0];

// Connect and query AD for OUs under base OU
var ldapClient = host.getLdapClient();
var searchResults = ldapClient.search(ldapDn, LdapSearchScope.SUB, LdapDereferencePolicy.NEVER, 99999, 0, "(objectClass=OrganizationalUnit)", ATTRIBS);
var entries = searchResults.getSearchEntries();
var adOUs = new Array();
 
// Define a comparator function that compares the 'name' attribute of each entry
function compareEntries(a, b) {
  var nameA = a.getAttributeValues("canonicalName")[0];
  var nameB = b.getAttributeValues("canonicalName")[0];
  return nameA.localeCompare(nameB);
}
 
// Sort the entries array using the comparator function
entries.sort(compareEntries);
 
// Loop through the sorted entries and append the sub-organizational unit path to each name
for each (var entry in entries) {
    var distinguishedName = entry.getAttributeValues("distinguishedName")[0];
    var name = entry.getAttributeValues("canonicalName")[0];
 
    // Remove "example.com/Servers/" from the name
    name = name.replace("example.com/Servers/", "");
    
    // Log output for debugging
    System.log(name);

    // Add the name and distinguishedName pair to the adOUs array
    adOUs.push(new Properties({value: distinguishedName, label: name}));
}
 
// Remove 'example.com/Servers' from index 0 of the array
adOUs.shift();
 
return adOUs;

The comments should spell out the process pretty clearly, but there are a few key takeaways:

  • Change “OU=Servers,OU=example,DC=com” to our base search OU
  • I had the luxury of only needing to configure a single domain and could be lazy selecting it, the script will need to be modified if more domains are present
  • AD search results need to be sorted if you want them to be easily digestible – this adds complexity; more on that later
  • “example.com/Servers/” needs to be removed from the canonical name for readability
  • Sub OUs/child OUs are left in the list and are easily readable i.e.:
    • SQL
    • SQL\Server 2019
    • SQL\Server 2022
  • The return type must be Properties with Array checked:

Create another Action with the same name, but append “unsorted”, i.e. getServerAdOuListUnsorted. The action is nearly identical, but the sorting function is removed and it returns Properties without Array checked.

// AD domain name
var adName = "example.com";
// Search base/root OU where server computer objects are
var ldapDn = "OU=Servers,OU=example,DC=com";

// Configure attributes that need returned from AD
var ATTRIBS = ['distinguishedName', 'canonicalName'];

// Get AD Host object from AD plugin library
var adHosts = AD_HostManager.findAllHosts();
var host = adHosts[0];

// Connect and query AD for OUs under base OU
var ldapClient = host.getLdapClient();
var searchResults = ldapClient.search(ldapDn, LdapSearchScope.SUB, LdapDereferencePolicy.NEVER, 99999, 0, "(objectClass=OrganizationalUnit)", ATTRIBS);
var entries = searchResults.getSearchEntries();
var adOUs = new Array();
 
// Loop through the sorted entries and append the sub-organizational unit path to each name
for each (var entry in entries) {
    var distinguishedName = entry.getAttributeValues("distinguishedName")[0];
    var name = entry.getAttributeValues("canonicalName")[0];
 
    // Remove "example.com/Servers/" from the name
    name = name.replace("example.com/Servers/", "");
    
    // Log output for debugging
    System.log(name);

    // Add the name and distinguishedName pair to the adOUs array
    adOUs.push(new Properties({value: distinguishedName, label: name}));
}
 
// Remove 'example.com/Servers' from index 0 of the array
adOUs.shift();
 
return adOUs;

Again, Array should be unchecked in the return type for this “unsorted” action:

Next, navigate over to Cloud Assembly and open your Cloud Template to begin connecting our Actions. Find the Inputs tab and click New Cloud Template Input.

Give it a Name, adOU, and Description. Choose type String, expand More Options, then toggle Enumerated list type to External source. This is where you type in and select your “unsorted” Action, i.e. getServerAdOuListUnsorted.

Here’s the catch for the set of sorted/unsorted actions: For some reason unknown to me, the Cloud Template will not accept a sorted array returned and this is the workaround. So, just give it the same data, unsorted and we’ll override it later. Hence why we need a second unsorted action. Kudos to Krisztian Kukis for documenting this workaround.

Here’s the YAML for the input. You can see that it’s bound to the vRO action:

adOU:
  type: String
  title: AD OU
$dynamicEnum: /data/vro-actions/com.example.ad/getServerAdOuListUnsorted

Next, navigate over to Service Broker and open up your customized form to edit. Once open, you should see a Schema Element for “AD OU” (or whatever you named it) under Request Inputs – make sure it’s added to the form.

Select our AD OU input to view the Properties pane. On the Appearance tab, choose a display type of Dropdown or Combobox. Either will suffice, I found Combobox to suit hundreds of OUs best.

Finally, we can finish putting everything together. Switch over to the Properties pane Values tab. Select External source for the Value source. In the Select action field, search for your sorted action, i.e. getServerAdOuList. Here we use the workaround to override Cloud Template.

Save your custom form and that’s it. Navigate to your Catalog item and test it out.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.