vCenter Orchestrator workflow to renew vCloud Director vApp leases

In vCloud Director (vCD), vApp leases are defined at the organization level and can’t be overridden at the vApp level.  In our dev/test cloud we set leases so that vApps will expire after a certain amount of time.  We do this so that unused vApps will expire and users can continue to deploy new vApps without the need for further increasing their vApp quota.  Users receive emails that their vApps are about to expire and they can renew them at any time, but I thought I’d look into a way of creating an exception list for vApps that should never expire.

I decided on using vCenter Ochestrator (vCO) to accomplish this for the following reasons:

  • We already use heavily in our vCD environment.
  • A vCO workflow has a graphical interface for adding/deleting vApps from the exception list.
  • The workflow will reside on the vCO server and not on some other server where it’s more likely to be forgotten.
  • I can use the built-in vCO scheduler to run the workflow.
  • If needed, I can make an API call to run the workflow externally.

The workflow

I’m not going to document each step of creating the workflow, but I’ll list what each workflow component looks like so you can see the inputs, outputs and code.

Workflow overview


Workflow attributes


vApps Left?





Get current vApp







vApp exist?





Update Leases







leaseSettingsSection = currentVapp.getLeaseSettingsSection()

System.log("Updating runtime lease for vApp: " + + ". Current lease is: " + leaseSettingsSection.deploymentLeaseInSeconds)
System.log("Updating storage lease for vApp: " + + ". Current lease is: " + leaseSettingsSection.storageLeaseInSeconds)

newDeploymentLeaseInSeconds = currentVapp.parent.parent.toAdminObject().settings.vAppLeaseSettings.deploymentLeaseSeconds
newStorageLeaseInSeconds    = currentVapp.parent.parent.toAdminObject().settings.vAppLeaseSettings.storageLeaseSeconds

leaseSettingsSection.deploymentLeaseInSeconds = newDeploymentLeaseInSeconds
leaseSettingsSection.storageLeaseInSeconds    = newStorageLeaseInSeconds

var task = currentVapp.updateSection(leaseSettingsSection)




Adding vApp(s) to the workflow

Edit the workflow:


Select the vApp attribute’s value:



Browse to vCloud Director > vCD instance > Organizations > Org that your vApp(s) are in > vDCs > vDC your vApp(s) are in > vApps


Add each of the vApps that you want to renew the leases on.


Once you’re done, you’ll see the list of vApps in the vApps attribute array:


Example of a successful run:


Scheduling the workflow


Select your workflow:


Set the scheduling times for whatever makes sense in your environment:


Finished schedule:


Re-associating vCloud Director VMs with the correct resource pool

Our team was upgrading ESXi hosts in our vCloud Director environment and all of the VMs must have not have migrated when placing the hosts into maintenance mode so they manually migrated the VMs.  Since we have multiple org vDCs, we have multiple resource pools.  As you may know, when you try to migrate VMs that are in multiple resource pools, the migration wizard only allows you to place the VMs in a single resource pool.  I started seeing the following system alert on all of the vCloud Director VMs:


I checked vCenter and sure enough all of the VMs were in the root resource pool (the cluster), and no longer in the correct resource pool.  If you migrate the VMs one at a time, the migration wizard automatically places the VM in the correct resource pool, but the team didn’t want to do this as it would take too much time.  If you do have to migrate the VMs manually, you can migrate VMs in bulk and have the migration wizard place the VMs in the correct resource pool if you use the following process:

  1. Select a resource pool.
  2. Select the Related Objects tab.
  3. Select Virtual Machines.
  4. Select all of the Virtual Machines.
  5. Select Migrate.


Here you can see that the wizard automatically selected the correct resource pool:


You still have to go through each resource pool and perform the migrations, but the VMs will retain the correct resource pool.  Of course, you could script it all as well.

So I was in the position of having all of the VMs in the wrong resource pool, which causes alarms in vCloud Director and could impact the performance of the virtual machines.  I could have went into vCloud Director and found each of the VMs individually, but this would have taken forever so I decided to use PowerCLI to re-associate the VMs with the correct resource pool.

You’ll need to be connected to vCloud and all of your vCenter instances:

connect-ciserver cloud.corp.local

connect-viserver vc.corp.local

Paste the following function into PowerCLI:

function reassociatevCDRPs {
    Places vCloud Director virtual machines into the correct vCenter resource pools.  
    Places vCloud Director virtual machines into the correct vCenter resource pools.  This can be helpful when the VMs are moved from their resource pool during a task such as manual vMotion. 
  reassociatevCDRPs -org all -promptOnMove $false
  reassociatevCDRPs -org admin -promptOnMove $true

    [string] $org = "all",
    [string] $promptOnMove = $false

    $ovdcLookupTable = @{}
    $vmsToMove       = @{}

    # Build lookup tables
    $orgIds = @{}
    $orgNames = @{}
    search-cloud -querytype organization | % { $orgIds[$] = $; $orgNames[$] = $ }

    $orgVdcIds       = @{}
    $orgVdcNames     = @{}
    search-cloud -querytype AdminOrgVdc | % { $orgVdcNames[$] = $; $orgvDCIds[$] = $ }

    $vCDVMs = search-cloud -querytype adminvm

  $searchCommand = "search-cloud -querytype adminvm"

  if ($org -ne 'all') {
    # Throw an error if the organization is not found in the vCloud instance.  Otherwise add a filter to the search-cloud command to only work on the supplied organization.
    if (! $orgIds[$org]) { throw "Organization $org not found." }  
    $searchCommand += " -filter org==$($orgIds[$org])"

  $vcdVMs = invoke-expression $searchCommand

    $vcdVMs | % { 
      $vcdVM = $_
      # Get the resouce pool name in the format of: orgVDC Name (UUID)
      $vcdRPName = "$($orgVdcNames[$vcdVM.Vdc]) ($($_.Vdc.split(':')[3]))" 

      $vcVM = get-vm -id "VirtualMachine-$($vcdVM.moref)"
      $vcRP = $vcVM.resourcepool 
      $vcRPName = $
      if ($vcdRPName -ne $vcRPName) {  # Test to see if vCD's resource pool matches vCenter's resource pool. 
        echo "$($ is in the resource pool '$($vcRPName)' and should be the '$($vcdRPName)' resource pool."
        # Add to list of VMs that need to be moved.   
        $vmsToMove[$vcVM] = get-resourcepool $vcdRPName


    $vmsToMove.keys | % { 
      if ($promptOnMove -eq $true) {
        $response = read-host "Move $($ to the correct resource pool ($($vmsToMove[$_])) ( [y]es, [n]o, [a]ll )?"
        if ($response -eq 'n') { # If the user selects not to move the VM, try the next VM in the list.
        elseif ($response -eq 'a') {
          $promptOnMove = $false
      $resourcePool = $vmsToMove[$_] 
      echo "Moving $vm into resource pool $resourcePool"
      move-vm $_ -Destination $resourcePool | out-null
      #echo "result: $($?)"


To correct all VMs with no prompting:

reassociatevCDRPs -org all -promptOnMove $false

To move VMs to a specific org and to prompt before each move:

reassociatevCDRPs -org “org name” -promptOnMove $true

This script won’t move shadow VMs, but those are easy… for each cluster just select them all and drag them into the cluster’s System vDC (uuid) resouce pool.  vShield Edges also won’t be moved.  Those will likely need to be moved into the System vDC resource pool as well or if they are a fenced vApp, they will go into an org vDC resource pool.  Or you can just de-deploy them and they should go to the correct resource pool.