RSS .92| RSS 2.0| ATOM 0.3
  • Home
  • About

    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 =@()
    (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 =@()
    (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 =@()
    (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 :
    [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 :
    [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: Calculate the allocated size, in GB, of a catalog in vCloud Director

    October 17th, 2013

    Here is a quick hitter for you to calculate the size, in GB, of a catalog in vCloud Director:


    -catalog <catalog name>

    param (
     [string]$catalog = $(throw 'Catalog Required')
    (get-catalog $catalog| get-civapptemplate) |% {
    "{0:N0}" -f $storagegb

    NOTE: The tricky-trick with {0:N0} can be found here.

    Generate a List of PoweredOn vApps per User in vCloud Director

    October 11th, 2013

    It is important to know what your users are doing in vCloud Director with the content, how many vApps that have Powered On and each user’s memory allocation.

    Here is how to do it!

    This code assumes you are logged in as System Admin role.

    (get-org ) |% {
     $org = $_
     ($org | get-ciuser) |% {
     $user = $_
     $vmCount = $user.deployedvmcount
     $storedCount = $user.storedvmcount
     if ($vmCount -gt 0) {
     ($user | get-civapp) |% {
     $array += $user
     $civapp = $_
     $civappStatus = $civapp.status
     $memAlloc = [math]::round($civapp.MemoryAllocationGB,0)
     if ($civappStatus -ne "PoweredOff") {
     $totalMem = $totalMem + $memAlloc
     write-host "$org,$user`n Deployed VM Count:$vmcount`n Stored VM Count: $storedCount`n Deployed/PoweredOn vApps: $uservAppCounter`n Total Memory Allocated: $totalMem GB"
     $grandTotalMem = $grandTotalMem + $totalMem
    write-host "`nTotal memory allocated: $grandTotalMem GB`nTotal users with deployed vApps: $counter"

    The up to date code can also be pulled from my GitHub repo!

    PowerCLI: Find unhealthy vApps in vCloud Director

    January 24th, 2013

    Ever wonder what vApps that have been deployed inside vCloud Director are in a bad state, and need investigation?  Me too!  Here’s a code block to find vApps that are NOT in the following states:

    • PoweredOn
    • PoweredOff
    • Suspended
    # set up the logfile
     $results = @()
     $logFile = "OUTPUT-unhealthyVApps.txt"
    # walk the connected Orgs, best if run as SysAdmin
     (get-orgvdc) | %{
    $orgVdc = $_
     $orgVdcName = $
    ($orgVdc | get-civapp) | %{
    $vApp = $_
     $vAppName = $
     $vAppStatus = $vApp.status
    if(($vAppStatus -ne "PoweredOn") -and ($vAppStatus -ne "PoweredOff") -and ($vAppStatus -ne "Suspended")) {
    write-host "vApp Name:"$vAppName
     write-host " Org vDC:"$orgVdcName
     write-host " Status:"$vAppStatus"`n"
    $results += "vApp Name: $vAppName"
     $results += " Org vDC:$orgVdcName"
     $results += " Status:$vAppStatus"
    (get-ciVM -vapp $vAppName) | %{
     $VM = $_
     $vmName = $
     $vmStatus = $vm.status
     write-host " VM: $vmName"
     write-host " Status:"$vmStatus"`n"
    $results += " VM: $vmName"
     $results += " Status: $vmStatus"
     $results += " "
    $results | out-file $logFile
     write-host "Output file is:"$logfile

    The code will display the following to the screen, and a logfile:

    vApp Name: vApp-vubuntu001
    Org vDC: ohio-demo_ovDC
    Status: Resolved

    VM: vApp-vubuntu001
    Status: PoweredOff

    This may mean that the VM’s that are contained in the vAPP don’t exist anymore, but the vAPP does.  A good one to check out!

    PowerCLI: Set bits to allow for ESXi nested virtualization

    January 23rd, 2013

    This post details totally unsupported materials!

    If you are spinning up nested virtualization, check the blog posts at virtuallyGhetto to set up the environment.

    In order to allow for the nested ESXi, a bit has to be checked to allow for Hardware Virtualization

    CPU hardware options

    Wouldn’t it be nice to set the bit via PowerCLI?  Yes, I think it would.  Here is the code:

    # set the guestOS string from vCenter to look for
     $guestOSname = "VMware ESXi 5.x"
    # options we need to set for nested virtualization
     $vmxValue = "NestedHVEnabled"
     $boolValue = "TRUE"
    # walk vCenter and determine VM's that match $esxiGuest
     (get-vm) | %{
     $vm = $_
    $guestType = ($view).summary.config.guestFullName
    # do equality string checks and proceed to remediate if
     # $esxiGuest is found
     if ( $guestType -eq "$guestOSname") {
     write-host "`nFound VM:"$ "with guest type:"$guestOSname
    # push the value to the VM
     write-host "Now Setting bits for nested virtualization...`n"
    $vmValue = (get-vm $vm | get-view)
     $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
     $vmConfigSpec.$vmxValue = $boolValue

    The magic bit is NestedHVEnabled which will set vhv.enable = TRUE in the .vmx file of the VM.  That is where the magic happens.  It can be found in the public API documentation.

    Once you run the code, check the CPU config and you will see the box checked.

    CPU hardware options post

    Be aware, this will find all of your ESXi virtual machines.