RSS .92| RSS 2.0| ATOM 0.3
  • Home

    Nutanix and Powershell – Automating Nutanix Cluster Operations

    September 3rd, 2014

    This blog post details the use of the mega awesome Nutanix Powershell cmdlets to conduct, what in essence, are one-time operations to configure a Nutanix cluster.

    We will cover operations to define DNS, NTP and SMTP servers and re-use code from a previous blog post to create a Storage Pool and Container.

    We are going to leverage the following Nutanix Powershell cmdlets:

    • get-NTNXnameServer
    • remove-NTNX-nameServer
    • add-NTNXnameServer
    • get-NTNXntpServer
    • remove-NTNXntpServer
    • add-NTNXntpServer
    • remove-NTNXsmtpServer
    • set-NTNXsmtpServer
    • get-NTNXdisk
    • new-NTNXstoragePool
    • new-NTNXcontainer
    • add-NTNXnfsDatastore
    • set-NTNXcluster

    Pretty easy really.  One option that stands out is the Nutanix Pulse verbosity level.  We can configure the following levels:

    • None
    • All
    • Basic
    • Basic-Coredump

    This defines the levels you, and Nutanix support, will receive describing platform status.

    ### [ Variable Definition ] ###
    # define DNS servers
    $nameServer1 = ""
    $nameServer2 = ""
    # define NTP servers
    $ntpServer1 = ""
    $ntpServer2 = ""
    # define SMTP settings
    $smtpServer = ""
    $smtpPort = "25"
    $smtpFromAddress = "email [at]"
    # define Storage parameters
    $storagePool = "SP1"
    $containerName = "NTNX-container001"
    # Pulse verbosity type
    $pulseLevel = "ALL"
    ### [ Main ] ###
    ## set DNS servers ##
    if( ($nameServer1.length -gt 0) -and ($nameServer2.length -gt 0) ) {
       # clean up old records
       [void](get-NTNXnameServer | remove-NTNXnameServer)
       write-host "Adding DNS servers: "$nameServer1","$nameServer2
       [void](add-NTNXnameServer -input $nameServer1)
       [void](add-NTNXnameServer -input $nameServer2)
    } else {
       write-host "Adding DNS server: "$nameServer1
       [void](add-NTNXnameServer -input $nameServer1)
    ## set NTP servers ##
    if( ($ntpServer1.length -gt 0) -and ($ntpServer2.length -gt 0) ) {
       # clean up old records
       [void](get-NTNXntpServer | remove-NTNXntpServer)
       write-host "Adding NTP servers: "$ntpServer1","$ntpServer2
       [void](add-NTNXntpServer -input $ntpServer1)
       [void](add-NTNXntpServer -input $ntpServer2)
    } else {
    write-host "Adding NTP server: "$ntpServer1
       [void](add-NTNXntpServer -input $ntpServer1)
    ## set SMTP server ##
    if( $smtpServer -gt 0) {
       #clean up old records
       write-host "Adding SMTP server: "$smtpServer
       [void](set-NTNXsmtpServer -address $smtpServer -port $smtpPort -fromEmailAddress $smtpFromAddress)
    ## create Storage ##
    $array [email protected]()
    (get-ntnxdisk) |% {
       $hardware = $_
       write-host "Adding disk "$" to the array"
       $array += $
    write-host "Creating a new storage: $storagePool"
    new-NTNXStoragePool -name $storagePool -disks $array
    write-host "Creating container: $containerName"
    new-NTNXContainer -storagepoolid $ -name $containerName
    sleep 3
    write-host "Adding container $containerName to ESXi hosts"
    add-NTNXnfsDatastore -containerName $containerName
    ## set Pulse verbosity level ##
    write-host "Setting Pulse verbosity level to: "$pulseLevel
    [void](set-NTNXcluster -supportVerbosityType $pulseLevel)

    Nutanix+Powershell – Provision a StoragePool, Container and Mount Datastore in Seconds

    August 19th, 2014

    The Nutanix platform is consistently iterating and adding quality new features with every release.

    Nutanix has released Powershell cmdlets with NOS version 4.0+.  This post will describe using said cmdlets to create a storage pool and container(s).

    A full brain dump of the Nutanix plaform can be found at the Nutanix Bible, and the data structure section in particular.

    Storage Pool

    On the storage side of the Nutanix platform, each node consists of X SSD and Y magnetic spinning disks.  Nutanix best practice states that 1, and only 1, Storage Pool be created per Nutanix cluster.  A Storage Pool encapsulates all disks on each node of the cluster.

    That being said, let’s dig in to what is required to automagically provision a storage pool and container on top!

    A requirement to create a storage pool, as described above, is to list and capture all disks available.  To do that, we leverage the get-ntnxdisk cmdlet:


    The output will be similar to:

    id : 43
    serviceVMId : 4
    lastServiceVMId : 0
    mountPath : /home/nutanix/data/stargate-storage/disks/BTTV333505WZ400HGN
    diskSize : 179289518899
    storageTierName : SSD-SATA
    storagePoolId :
    hostName : <redacted>
    cvmIpAddress : <redacted>
    clusterUuid : <redacted>
    markedForRemoval : False
    dataMigrated : False
    online : True
    diskStatus : NORMAL
    location : 1

    There will obviously be more disks.  We are looking for the value of id, and want to add them to an array:

    $array [email protected]()
    (get-NTNXdisk) |% {
       $hardware = $_
       write-host "Adding disk "$" to the array"
       $array += $

    We want to define a storage pool and container name:

    $storagePool = "SP1"
    $containerName = "NTNX-container001"

    Now let’s have some fun and create the storage pool:

    write-host "Creating a new storage pool: $storagePool"
    new-NTNXStoragePool -name $storagePool -disks $array
    # save the storagePool object for use with Container
    $newStoragePool = get-NTNXStoragePool

    At this point, if you browse to the Prism UI you will see our brand new storage pool called SP1.  You can also evaluate $newStoragePool


    In Nutanix land, a container is a logical segmentation of a Storage Pool, and is represented to the Hypervisor as a datastore.

    write-host "Creating container: $containerName"
    new-NTNXContainer -storagepoolid $ -name $containerName

    We just prepared an object that will be mounted as a datastore on the Hypervisors.  That quickly.  If you stop and think for a second, provisioning storage in a traditional three-tier architecture can take hours (creation of LUN, zoning, etc etc) and is fraught with errors.

    We are now going to mount the newly created container to the Hypervisors:

    write-host "Adding container $containerName to ESXi hosts"
    add-NTNXnfsDatastore -containerName $containerName

    Look at your VI Client.  The datastores are all mounted!  Bang!  That fast.  The Power of the Nutanix platform.


    To put it all together:

    $storagePool = "SP1"
    $containerName = "NTNX-container001"
    $array [email protected]()
    (get-ntnxdisk) |% {
       $hardware = $_
       write-host "Adding disk "$" to the array"
       $array += $
    write-host "Creating a new storage: $storagePool"
    new-NTNXStoragePool -name $storagePool -disks $array
    write-host "Creating container: $containerName"
    new-NTNXContainer -storagepoolid $ -name $containerName
    sleep 3
    write-host "Adding container $containerName to ESXi hosts"
    add-NTNXnfsDatastore -containerName $containerName

    (NOTE) I added a 3 tick sleep to make sure the new-NTNXContainer command had time to complete on the back end.

    Consuming Nutanix PrismAPI with Powershell – Display information about CVM

    March 19th, 2014

    A customer recently asked how to list the IP address of the Nutanix CVM (Controller Virtual Machine).

    I have already blogged how to consume the PrismAPI with vCenter Orchestrator.  This time we will use Powershell.

    PrismAPI exposes a whole bunch of awesome data.  In particular the /hosts/ endpoint is what we need:


    It will respond with:

    “entities”: [
    “serviceVMId”: 10,
    “name”: “NTNX-<redacted>-D”,
    “serviceVMExternalIP”: “192.168.2.”,
    “hypervisorAddress”: “192.168.2.”,

    But in reality, it will be one gigantic string/array blob.

    The following code will connect to your block, query the data and respond with the serviceVMid, CVM name, CVM IP and hypervisor IP.  Note: You will need Powershell 4.0 for the invoke-restmethod.

    Be sure to enter proper data to the <FILL THIS IN> sections.  Have fun!

    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
    #declare an array to be used later
    $array = @()
    $Uri = "https://:9440/PrismGateway/services/rest/v1/hosts/"
    $username = ""
    $password = ""
    $Header = @{"Authorization" = "Basic "+[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($username+":"+$password ))}
    $results = Invoke-RestMethod -Method Get -Uri $Uri -Headers $Header
    # grab the results of the entity section
    ($results.entities) |%{
    # set the output of the foreach to the $array var
    $array = $_
    #iterate through the array
    ($array) | %{
    write-host "`nname:"$ "`n serviceID:"$array.serviceVMid "`n externalIP:"$array.serviceVMExternalIP "`n hypervisorAddress:"$array.hypervisorAddress"`n"

    Connecting to the Nutanix PrismAPI with vCenter Orchestrator – Part 3

    March 4th, 2014

    Part 1 covered pointing the vCO HTTP-REST plugin to a PrismAPI endpoint.

    Part 2 covered building a workflow and consuming the bulk data output from the PrismAPI.

    Part 3 will cover consuming the data, and in this case displaying values from Nutanix Protection Domains.

    Add a Scriptable Task

    Right click on the workflow created in Part 2, and click Edit.  In my case, the workflow is called Nutanix PrismAPI – protection_domains.

    1. Drag a Scriptable Task to the blue line that connects Invoke a REST operation and the end ball.add parseJSON scriptable task
    2. Switch to the Info tab, and name it parseJSON.
    3. Switch to the IN tab, hit the single dumb bell, and select contentAsString  scriptable task input
    4. Change to the Scripting tab.  Plug in the following code:
    // built in JSON parser to vCO via javascript
    var jsonResponse = JSON.parse(contentAsString);
    // get the length of the JSON array that is returned
    // iterate through the array and look for particular values we want to use
    for(var i=0;i<length;i++) {
     for(obj in jsonResponse[i]) {
     if(obj == "name") {
     //System.log("object: "+obj);
     System.log("---> Protection_domain: "+jsonResponse[i][obj]);
     if(obj == "pendingReplicationCount") {
     System.log("---> pendingReplicationCount: "+jsonResponse[i][obj]);
     if(obj == "ongoingReplicationCount") {
     System.log("---> ongoingReplicationCount: "+jsonResponse[i][obj]);
     if(obj == "totalUserWrittenBytes") {
     System.log("---> foundTotalUserWrittenBytes: "+jsonResponse[i][obj]);

    Validate the workflow and fix any errors.  Right click and run.  My example output looks like this:

    [2014-03-04 15:50:20.402] [I] —> Protection_domain: WANPD2
    [2014-03-04 15:50:20.402] [I] —> pendingReplicationCount: 0
    [2014-03-04 15:50:20.403] [I] —> ongoingReplicationCount: 0
    [2014-03-04 15:50:20.403] [I] —> foundTotalUserWrittenBytes: null
    [2014-03-04 15:50:20.404] [I]

    [2014-03-04 15:50:20.404] [I] —> Protection_domain: WANPD
    [2014-03-04 15:50:20.405] [I] —> pendingReplicationCount: 0
    [2014-03-04 15:50:20.405] [I] —> ongoingReplicationCount: 0
    [2014-03-04 15:50:20.406] [I] —> foundTotalUserWrittenBytes: null
    [2014-03-04 15:50:20.406] [I]

    In my code, I am specifically looking for Protection Domains, and three values:

    • pendingReplicationCount
    •  ongoingReplicationCount
    • foundTotalUserWrittenBytes

    With code such as this, it could be possible to create a scheduled task, and send an alert email if the pendingRelicationCount hits a certain threshold.


    Editors note: Mobile shout-out to Ryan Swenson for code assist.

    Connecting to the Nutanix PrismAPI with vCenter Orchestrator – Part 2

    March 3rd, 2014

    Part 1 covered pointing the vCO HTTP-REST plugin to a PrismAPI endpoint.

    Part 3 will cover consuming the data, and in this case displaying values from Nutanix Protection Domains.

    Continuing on, we need to first Add a REST operation.  This, in short, defines an API endpoint we are going to conduct GET operations.  You can also configure endpoints to do POST operations, among others.

    We are going to create a generic endpoint that allows for variable substitution, which we will pass in.  The current PrismAPI endpoint allows for the following resources:

    • /alerts
    • /authconfig
    • /cluster
    • /containers
    • /disks
    • /events
    • /hosts
    • /http_proxies
    • /protection_domains
    • /remote_sites
    • /service_centers
    • /snmp
    • /storage_pools
    • /vdisks
    • /vms
    • /vstores

    I am going to pick /protection_domains, for no other reason than it will probably be a totally fun thing to build workflows against (such as monitoring in-flow replication).

    Add a REST operation

    We will consume the REST host we populated in the first tutorial.

    1. Expand Library->HTTP-REST.  Right-click on Add a REST Operation Add a REST Operation
    2. Select the Parent Host created in the 1st tutorial.  Mine is called “Nutanix PrismAPI”
    3. The REST Workflow leaves an entry for Name.  This can be specific a specific resource, in my case, I want to keep it generic and pass in a resource at runtime.  The PrismAPI is currently constructed thusly: /PrismGateway/services/rest/v1/<resource>/ .. vCO allows for variable substitution, so enter the following string: /PrismGateway/services/rest/v1/{endPoint}/
    4. The HTTP method is GET.  Click submit, and hopefully you have a green response.
    5. Now we get to the fun stuff.  Create a new folder somewhere in your vCO tree.  I called mine Nutanix PrismAPI
    6. Right click on the folder and select New Workflow.  I named mine: Nutanix PrismAPI – protection_domains.  I chose the naming to denote this WF (workflow) will be directly calling the protection_domains resource.
    7. In the general tab, create a new Attribute by clicking on the A+.  Name it restOperation (as so, it makes things easier in a bit).  Select the value, and  drill to the HTTP-REST host you have created for this.  Expand and select the red ball for the Operation.
    8. Create another Attribute and enter the value as protection_domains (again as thus, it is a hard requirement as it is called the REST resource).
    9. Create a final Attribute called contentAsString and leave the value blank.
    10. Great, now click on the Schema tab.  Drag a Workflow element from the left pain to the blue error between the green “Go” ball and the end ball.  In the filter field, type: “Invoke a REST Operation.”  Hit Select.Invoke RestOP WF
    11. Hover over and hit the pencil.  You will now edit the specifics of that WF element.  Hit Pencil
    12. Click the In tab.  For restOperation, click the Source paramenter field and select the restOperation that we created.input to null
    13. Click the Source Parameter for param_0, select the endPoint attribute we created.
    14. Set the rest to NULL.
    15. Click on the Out tab.  Set the contentAsString to the contentAsString attribute we created.output to content as string
    16. The other three Local Parameters can be set to NULL, or you can create attributes for each and wire them.  Hit OK.
    17. Click on the Validate button with the green check.  Hopefully everything is wired properly.  If not, investigate the fix.  Save and close.

    Run the Workflow

    1. Right click on the Workflow that was just created.  With any luck you should see the workflow run, step through and complete.  We will receive the following output (I prettied it up, just a little bit):

    [2014-03-03 20:29:57.546] [I] Request: DynamicWrapper (Instance) : [RESTRequest]-[class] — VALUE : [email protected]
    [2014-03-03 20:29:57.546] [I] Request URL: https://<URL>/PrismGateway/services/rest/v1/protection_domains/
    [2014-03-03 20:29:57.586] [I] Response: DynamicWrapper (Instance) : [RESTResponse]-[class] — VALUE : [email protected]
    [2014-03-03 20:29:57.587] [I] Status code: 200
    [2014-03-03 20:29:57.588] [I] Content as string: <A very long string in JSON format>

    We see awesome metrics such as:




    With this, we can theoretically build a workflow that monitors replication status and alerts us with progress and/or completion.  Parsing and using the data will be in Part 3!

    Connecting to the Nutanix PrismAPI with vCenter Orchestrator

    March 3rd, 2014

    REST API are fun to consume!  JSON is fun to consume and use!  vCenter Orchestrator is fun to use, and act as a consumer of data!

    Now that I work for Nutanix let us investigate different ways to consume the platform’s API!

    Editor’s note:  This will hopefully end up being a series of posts.  The post is a bit of a homage to content produced by other people:

    • Jason Langone’s series
    • Andre Leibovici’s posts via on the Nutanix API, and using PowerCLI (multiple)
    • Josh Gray’s series of posts on about using vCO to do many cool things

    Special blog-style shout-out to Sasha Armstrong for granting me access.

    Read them all.  There is great content available.

    Editor’s note #2: This post assumes a working installation of vCenter Orchestrator with the HTTP REST plugin imported and available.  The bits can be found at your local VMware download site.


    • URL of your Nutanix PrismAPI endpoints
    • username and password
    • Most likely an open window pointing at the Rest API Explorer Live! page of your Nutanix endpoint (can be found by dropping-down next to your user name and selecting)

    Add a REST host

    First we need to add a REST host endpoint to vCO.

    1. Under the Run view, select the Workflows widget.
    2. Expand Library -> HTTP-Rest -> Configuration folders
    3. Right click on Add a REST host and select Start Workflow
    4. Enter something usable under the Name field (note this helps identify your REST endpoint if you have multiple.  So entering foo is not advised)
    5. Enter the URL, including http(s) and/or port (if non-standard) as required.  example:
    6. Click Next.
    7. Select the appropriate Bool value for Proxy settings, and enter specifics, if necessary.  Click Next.
    8. Select Basic from the Host Authentication drop-down.
    9. Use Shared session mode.
    10. Enter a username and password that has permissions to authenticate to the Nutanix PrismAPI and click Submit.

    Hopefully at that point you have a successful connection to the host.  If a failure was generated, re-run the workflow and fix the errors.

    Part 2 will cover building a workflow and consuming the bulk data output from the PrismAPI.

    Part 3 will cover consuming the data, and in this case displaying values from Nutanix Protection Domains.

    PowerCLI – Report on Organization Resource usage in vCloud Director

    December 6th, 2012

    It is important to monitor Organization resource usage in vCloud Director.  There is a view in the Monitor area but what if you want a quick look?  Voila, here it is!

    You will need PowerCLI installed with the vCloud cmdlets.  You will also need to be connected to the cell.  This will walk through all of your configured Organizations and display the percentage usage.  Very useful when you are using the Allocation model.

    (get-orgvdc) | %{
     $orgvdc = $_
     $cpuAlloc = $orgvdc.CpuAllocationGhz
     $ramAlloc = $orgvdc.MemoryAllocationGB
     $storAlloc = $orgvdc.StorageAllocationGB
     if ($orgvdc.CpuUsedGhz -ne 0 -and $orgvdc.CpuAllocationGhz -ne 0) {
     $orgcpuspc = (($orgvdc.CpuUsedGhz * 100) / $orgvdc.CpuAllocationGB) }
     if ($orgvdc.MemoryUsedGB -ne 0 -and $orgvdc.MemoryAllocationGB -ne 0) {
     $orgramuspc = (($orgvdc.MemoryUsedGB * 100) / $orgvdc.MemoryAllocationGB) }
     if ($orgvdc.StorageUsedGB -ne 0 -and $orgvdc.StorageAllocationGB -ne 0) {
     $orgstoruspc = (($orgvdc.StorageUsedGB * 100) / $orgvdc.StorageAllocationGB) }
     $orgram = [System.math]::round($orgramuspc,1)
     $orgcpu = [System.math]::round($orgcpuspc,1)
     $orgstor = [System.math]::round($orgstoruspc,1)
     write-host `n"Org vDC: $orgvdc"
     write-host "CPU: $orgcpu% of $cpuAlloc Ghz, MEM: $orgram% of $ramAlloc GB, Storage: $orgstor% of $storAlloc GB"`n

    The output will be:

    OvDC: My Org vDC, CPU: 25.3%, MEM: 18.6%, Storage: 60.1%

    vCloud Director not generating discreet BIOS UUID by default

    November 14th, 2012

    vCloud Director in the 1.x series does not generate discreet BIOS UUID by default.  This item is documented in two KB’s that I was able to find:

    Prior to running the SQL statement, which must be run against the vCloud Database, dbo.config table (which is not really clearly mentioned), all VM’s deployed in a vApp do not get the discreet BIOS UUID, and at least in the case of Windows 2008, all machines will than generate the same OS GUID.  This may or may not be bad depending on your circumstances.

    You can look at the .vmx of each machine to determine if the BIOS UUID is the same, or run two quick PowerShell commands:

    To show the BIOS UUID inside Windows 2008 guest OS:

    get-wmiobject win32_computersystemproduct

    To show the Windows UUID, run:

    get-wmiobject win32_computersystemproduct |select-object -expandproperty uuid

    When we conducted the change, I shut down the cell to guarantee there were no writes to the database from vCD’s perspective.  We ran the SQL statement, started the cell and deployed new machines.  Each one had a new BIOS UUID and Windows GUID.

    PowerCLI: Add VM’s in vApp, within vCloud Directory to Security Groups withing vShield App

    October 3rd, 2012

    The title says it all!  The use case:

    You are using vCloud Director, and want to add Virtual Machines from deployed vApps to specific Security Groups within vShield App.  In my case, there were three Security Groups created to make a 3-tier environment.  Web, App and Database.

    Once again Alan Renouf came through by creating a vShield module for PowerCLI.  Follow the directions in his video to install it.  It’s actually quite easy.

    The script I am going to list below requires valid connections to three sources in order to do the work:

    1. The vCenter that manages the compute nodes in your vCloud
    2. The vCloud Director cell.
    3. The vShield Manager for the vCloud stack.

    (You also need to be licensed for vShield App.)

    Prior to connecting to vShield Manager, you will need to instantiate the module Alan created.  That _should_ have been done when watching his video, but if not, do:

    import-module vshield

    within PowerCLI.

    At this point you can connect to your three services:

    • connect-viserver <for vCenter>
    • connect-ciserver <for vCloud Director>
    • connect-vshieldserver <for vShield Manager>

    Ok, so now hopefully our connections are set up.  Let’s describe the script a little more.  As I said before, the use case was to create a 3-tier environment via vShield App: Web, App and DB.  Our VM’s in the vApp are conveniently named “WWW,” “APP” or “DB.”  We are sort of cheating, and keying off that nomenclature to identify the VM’s.

    We have three hardcoded security groups in the script: Web, App and DB.  Their variables are $SGWeb, $SGApp and $SGDb.  I know I am clever.

    We are going to provide the name of a vAPP in vCloud Director from the command line.  This script will then walk the contents of the vApp, which are our three servers.  For those who are heavily involved in vCloud Director, you know that each VM in vCenter is identified by <VMNAME> (vCloud UUID).  In order for us to add a VM to vShield App, which is tied to vCenter, we must actually push that naming nomenclature.  I’m frankly not the best at coding, so I had to cheat and use the trim() function twice in order to pull the UUID out of the urn:vcloud:vm:uuid string.

    At that point, we use PowerShell’s like function to do string comparison, and then run Mr. Renouf’s set-vshieldsecuritygroup in order to place the VM in to appropriate vShield App Security Group.  That command is covered in his movie.  I hope you find it useful!

    Usage: ./<scriptname>.ps1 -vapp <vAPP name in vCD> -datacenter <the datacenter object where your vCD and vShield are attached>

    param (
    # Hardcode Security Groups, for now
    $SGWeb = "Web"
    $SGApp = "App"
    $SGDb = "DB"
     Foreach ($VM in (get-CIVM -vapp $vApp)) {
     $vCloudVM = $
     write-host "VM name: " $vCloudVM
     $vCloudID = $
     write-host "vCloud ID: " $vCloudID
     # for whatever reason the trim() function cuts off too much
     # so I had to trim twice. beats me why...
     $vCloudIDtrim = ($vCloudID).trim("urn:vcloud:")
     $vCloudIDtrim = ($vCloudIDtrim).trim("m:")
     write-host "Trimmed vCloud ID: " $vCloudIDtrim
     if ($vCloudVM -like '*www*'){
     write-host "Adding $vCloudVM to Security Group $SGWeb..."
     # add VM to SecurityGroup
     set-vShieldSecurityGroup -Add -Datacenter (get-Datacenter $dataCenter) -SecurityGroup $SGWeb -VM (Get-VM "$vCloudVM ($vCloudIDtrim)")
     elseif ($vCloudVM -like '*app*') {
     write-host "Adding $vCloudVM to Security Group $SGApp ..."
     # add VM to SecurityGroup
     set-vShieldSecurityGroup -Add -Datacenter (get-Datacenter $dataCenter) -SecurityGroup $SGApp -VM (Get-VM "$vCloudVM ($vCloudIDtrim)")
     elseif ($vCloudVM -like '*db*') {
     write-host "Adding $vCloudVM to Security Group $SGDb ..."
     # add VM to SecurityGroup
     set-vShieldSecurityGroup -Add -Datacenter (get-Datacenter $dataCenter) -SecurityGroup $SGDb -VM (Get-VM "$vCloudVM ($vCloudIDtrim)")

    The output will be of the form:

    VM Name: www001
    vCloudID: urn:vcloud:vm:<UUID>
    Trimmed vCloudID: <UUID>
    Adding www001 to Security Group Web …

    ID : securitygroup-nn
    Datacenter : datacenter
    Member : @{name=www001 (<UUID>); object
    TypeName=VirtualMachine; objectId=<moref>}
    Description :
    Name : Web

    PowerCLI – Disable Host in vCloud Director and place host in Maintenance mode

    September 24th, 2012

    Since I am heavily involved in a vCloud deployment, I have asked many many VMware employees how we can make it easier for our operations staff conduct maintenance on an ESXi server.  As you may or may not know, an ESXi host that is prepared and being used by vCloud Director should be disabled and all virtual machines migrated off prior to maintenance.  In order to accomplish this action, a host must be disabled in vCloud Director, and then placed in to maintenance mode in vCenter.  Two separate interfaces.

    I met Alan Renouf after his PowerCLI session at VMworld 2012, and asked him if he knew of a way to disable a host via PowerCLI.  And he did!  Alan has created a function to conduct enable and disable operations.  He gave me permission to include it in the following code I built as a wrapper to conduct the operation from a command line via PowerCLI.


    1. PowerCLI installed with the vCloud Director cmdlets.  This is an option at install time, and is disabled by default (for whatever reason).
    2. vCloud Director (naturally)
    3. My script.
    First start PowerCLI.

    In order to connect to vCloud Director, first instantiate a connection via

    Connect-CIServer <vCloud Director cell>

    Start a session to the vCenter server that manages the vCloud pod via

    connect-VIServer <vCenter server>

    Now run the script.  There are two options from the command line -server <ESXi server name> and -state <enable/disable>.

    An example run would be: ./conductMaintenanceVCD.ps1 -server esxi001 -state disable

    Watch vCD and vCenter and be wowed.  Thanks again to Alan for creating the Disable-CIHost and Enable-CIHost functions!

    param (
    ## Enable/Disable-CIHost function provided by Alan Renouf
     Function Disable-CIHost {
     Param (
     Process {
     $Search = Search-cloud -QueryType Host -Name $CIHost
     #$HostEXT = $search.ExtensionData
     $HostEXT = $Search | Get-CIView
     # Disable the host in vCloud Director
     if ($HostEXT.Enable) {
    Function Enable-CIHost {
     Param (
     Process {
     $Search = Search-cloud -QueryType Host -Name $CIHost
     #$HostEXT = $search.ExtensionData
     $HostEXT = $search | Get-CIView
     # Disable the host in vCloud Director
     if ($HostEXT.Disable) {
    # conduct work on input
    write-host "Conducting $state operation on $server..."
    if ($state -eq "enable"){
     $serverState = get-vmhost $server
     if ( $serverState.ConnectionState -eq "Maintenance") {
     write-host "Taking $server out of maintenance mode"
     $returnCode = set-VMhost -VMHost $server -State Connected
     # sleep for 45 seconds for the host to exit maintenance mode.
     start-sleep -s 45
     write-host "Enabling host in vCloud Director"
     Enable-CIHost -CIHost $server
     elseif ($state -eq "disable"){
     write-host "Disabling host in vCloud Director"
     Disable-CIHost -CIHost $server
     # sleep for 5 seconds for the host to disable in vCD
     start-sleep -s 5
     write-host "$server entering maintenance mode"
     $returnCode = set-VMhost -VMHost $server -State Maintenance -Evacuate