| | | |

Automating Citrix PVS on Nutanix AHV with PoSH v2

4 min read

PowershellAfter our release of full support for Citrix PVS running on Nutanix AHV the blogpost I wrote on Automating Citrix PVS on Nutanix AHV with PoSH  in 2015 was obsolete until I got a question around this and I figured that I could update the script with the new PVS cmdlets (and it needed some finetuning as well). 

When we look at the current ways to interact with the Nutanix environment we basically can define 3 ways of doing so in a programmatically way:

  • REST API
  • CLI – ACLI & NCLI
  • Scripting interfaces (PoSH)

Both the scripting interfaces as the CLI follow the REST API, the REST API will be able to provide the full feature set of the Prism UI. This is important to understand as it will enable automation frameworks like Puppet, Chef, vRealize, etc to automate and orchestrate workflows within Nutanix.

Now Citrix PVS comes with PoSH as well and with living through previous interations of the Powershell implementation in PVS I can honestly say that there’s a lot of improvement there. If you combine the Nutanix cmdlets and the PVS cmdlets the easy to follow steps are as following:

  1. Create a target VM following your specifications
  2. Run the provided script, it will ask for the preferred VM and it will clone the VM according to your needs (copying VM resources specs).
  3. The script will then create a Target VM within the PVS console according to the naming scheme you have provided and it will fetch the MAC address from the VM and add it to the PVS console.

Although this is not fully integrated it gives you an idea of the capacities this platform has and how we can make things easier if we automate tasks.

# kees@nutanix.com
# @kbaggerman on Twitter
# https://blog.myvirtualvision.com
# Created on March 5, 2019


# Setting parameters for the connection
[CmdletBinding(SupportsShouldProcess = $False, ConfirmImpact = "None") ]
 
Param(
    # Citrix PVS Server IP
    [Parameter(Mandatory = $true)]
    [Alias('PVS Server IP')] [string] $ctxIP,
    # Nutanix cluster IP address
    [Parameter(Mandatory = $true)]
    [Alias('IP')] [string] $nxIP,   
    # Nutanix cluster username
    [Parameter(Mandatory = $true)]
    [Alias('User')] [string] $nxUser,
    # Nutanix cluster password
    [Parameter(Mandatory = $true)]
    [Alias('Password')] [System.Security.SecureString] $nxPassword
)
 
 Function write-log {
    <#
       .Synopsis
       Write logs for debugging purposes
       
       .Description
       This function writes logs based on the message including a time stamp for debugging purposes.
    #>
  param (
  $message,
  $sev = "INFO"
  )
  if ($sev -eq "INFO"){
    write-host "$(get-date -format "hh:mm:ss") | INFO | $message"
  } elseif ($sev -eq "WARN"){
    write-host "$(get-date -format "hh:mm:ss") | WARN | $message"
  } elseif ($sev -eq "ERROR"){
    write-host "$(get-date -format "hh:mm:ss") | ERROR | $message"
  } elseif ($sev -eq "CHAPTER"){
    write-host "`n`n### $message`n`n"
  }
} 


# Adding PS cmdlets for Nutanix
$loadedsnapins=(Get-PSSnapin -Registered | Select-Object name).name
if(!($loadedsnapins.Contains("NutanixCmdletsPSSnapin"))){
   Add-PSSnapin -Name NutanixCmdletsPSSnapin 
}

if ($null -eq (Get-PSSnapin -Name NutanixCmdletsPSSnapin -ErrorAction SilentlyContinue))
{
    write-log -message "Nutanix CMDlets are not loaded, aborting the script"
    break
}

# Adding PS cmdlets for Citrix PVS
$loadedsnapins=(Get-PSSnapin -Registered | Select-Object name).name
if(!($loadedsnapins.Contains("McliPSSnapIn"))){
   Add-PSSnapin -Name Citrix.PVS.Snapin 
}

if ($null -eq (Get-PSSnapin -Name Citrix.PVS.Snapin -ErrorAction SilentlyContinue))
{
    write-log -message "Citrix PVS cmdlets are not loaded, aborting the script"
    break
}

 
# Connecting to the Nutanix Cluster
try
{
    $nxServerObj = Connect-NTNXCluster -Server $nxIP -UserName $nxUser -Password $nxPassword -AcceptInvalidSSLCerts
    write-log -message "Connecting to the Nutanix Cluster with IP: $nxIP"
}
Catch 
{
if ($null -eq (get-ntnxclusterinfo))
{
    write-log -message "Cluster connection isn't available, aborting the script"
    break
}
}


# Connecting to the Citrix PVS server
Try
{
Set-PVSConnection -Server $ctxIP
write-log -message "Connecting to the PVS server with IP: $ctxIP"
}
Catch
            {
            write-log -message "Failed to connect to PVS Server $ctxIP"
            }
 
# Create VMs in AHV

 ##########################
 ## Get inputs & Defaults
 ##########################
 
 # Get vms array once
 $vms = Get-NTNXVM
 
 # Create array for clone tasks
 $cloneTasks = @()

 # Get available images
 if ($vmid.vmName -contains $image.vmName) {
 Write-Host "$($vmid.vmName)"
 }
 else {
 Write-Host "No Images found!"
 Write-Host "Please provide a VM name"
 }

 # Select Image
 if ([string]::IsNullOrEmpty($image)) {
 $image = Read-Host "Please enter an image name "
 } 

 # Get VM prefix if not passed
 if ([string]::IsNullOrEmpty($prefix)) {
 $prefix = Read-Host "Please enter a name prefix and int structure [e.g. myClones-###] "
 }
 
 # Get starting int if not passed
 if ([string]::IsNullOrEmpty($startInt)) {
 $startInt = Read-Host "Please enter a starting int [e.g. 1] "
 }
 
 # If ints aren't formatted
 if ($prefix -notmatch '#') {
 $length = 3
 } else {
 $length = [regex]::matches($prefix,"#").count
 
 # Remove # from prefix
 $prefix = $prefix.Trim('#')
 }
 
 # Get VM quantity if not passed
 if ([string]::IsNullOrEmpty($quantity)) {
 $quantity = Read-Host "Please enter the desired quantity of VMs to be provisioned "
 Write-Host ""
 }
 

 1..$quantity | %{
 
 $l_formattedInt = "{0:D$length}" -f $($_+$startInt-1)
 
 $l_formattedName = "$prefix$l_formattedInt"

 $lines = @($l_formattedName)
 
 
 
 # Create clone spec
 $spec = New-NTNXObject -Name VMCloneSpecDTO
 $spec.name = $l_formattedName

 foreach($vm in $vms) {
if($image -eq $vm.vmname) {
        $vmid = $vm.uuid} 
        }
 
 foreach ($p in $lines) {
 Clone-NTNXVirtualMachine -Vmid $vmid -SpecList $spec | Out-Null
 Write-log -Message "Creating clone $p" 
 }
}

# Parameters which have to be edited according to PVS Device Collection
$collection= "Collection"
$site= "Site"

# Get the VM Names, the MAC addresses and create targets in PVS
$vmid = get-ntnxvm | Where-Object {$_.vmName -Match $Prefix} | Sort-Object vmName
 foreach ($p in $vmid) {
 $mac = get-ntnxvmnic -vmid $p
 new-pvsdevice -deviceName $p.vmName -collectionName $collection -siteName $Site -deviceMac $($mac.macAddress -replace ":", "-") | Out-Null
 write-log -message "PVS Target created: $($p.vmName) with the mac address $($mac.macaddress) in site $($site)"
 }

Disconnect-NTNXCluster *
 
write-log -message "Disconnecting from the cluster"

Hopefully this helped to show another expample of the power of the shell. Here’s the output on my test system after running this script:

Running the script
The following two tabs change content below.

Kees Baggerman

Kees Baggerman is Senior Technical Director — Performance & Solutions Engineering R&D at Nutanix, where he leads a global team responsible for defining how enterprise applications are delivered on the Nutanix platform. A former Citrix Technology Professional and NVIDIA Enterprise Platform Advisor, he has spent 15+ years driving EUC strategy and technical direction across architecture, product, and customer success. He has been writing here since 2011 — sharing what he learns at the intersection of platform engineering and enterprise IT.
Kees Baggerman

Kees Baggerman

Senior Technical Director at Nutanix - Former Citrix CTP - NVIDIA Enterprise Platform Advisor - 15+ years in EUC

Kees Baggerman is Senior Technical Director — Performance & Solutions Engineering R&D at Nutanix, where he leads a global team responsible for defining how enterprise applications are delivered on the Nutanix platform. A former Citrix Technology Professional and NVIDIA Enterprise Platform Advisor, he has spent 15+ years driving EUC strategy and technical direction across architecture, product, and customer success. He has been writing here since 2011 — sharing what he learns at the intersection of platform engineering and enterprise IT.

Similar Posts

2 Comments

  1. Hi, do you have any guide on Integration of PVS with AHV, How do you manage DHCP and PXE boot, We have PVS , Xendesktop and VDI resouce hosted on VMWARE with BDM boot, we would like to now start with hosting VDI in the AHV hypervisor and then move the PVS server as well.

    Needed some guide if possible on how to achieve this using same VLAN presented to vmware and able to DHCP and PXE boot from AHV.

    1. That’s no problem, you can do PXE across the stretched VLAN across the hypervisors. Just make sure you’ve got the VirtIO drivers in the PVS image and you’re good to go

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.