After 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:
- Create a target VM following your specifications
- 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).
- 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# kees@nutanix.com # @kbaggerman on Twitter # http://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:
Kees Baggerman
Latest posts by Kees Baggerman (see all)
- Nutanix AHV and Citrix MCS: Adding a persistent disk via Powershell – v2 - November 19, 2019
- Recovering a Protection Domain snapshot to a VM - September 13, 2019
- Checking power settings on VMs using powershell - September 11, 2019
- Updated: VM Reporting Script for Nutanix with Powershell - July 3, 2019
- Updated (again!): VM Reporting Script for Nutanix AHV/vSphere with Powershell - June 17, 2019
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.
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