Exploring advanced scripts with XenServer PowerShell cmdlets

With XenServer PowerShell cmdlets, sometimes basic commands aren’t enough. Keep these advanced scripts in your arsenal for slicker management.

A Citrix management toolbox isn’t complete without XenServer PowerShell cmdlets, which allow admins to manage Citrix XenDesktop, XenApp, Provisioning Server, Netscaler and XenServer -- all within a single command-line interface.

Basic XenServer PowerShell cmdlets offer some key benefits in a virtual environment. They allow admins to copy virtual machines (VMs), determine the pool master, configure licensing and host editions and assign a home server to a VM. But virtual environments are nothing but basic; administrators often need to use advanced scripts and one-liners to further streamline and automate tasks.

Getting started with XenServer PowerShell cmdlets

To install XenServer PowerShell cmdlets on Windows 7 x64, admins need to download the XenServer PowerShell Snap-In and extract the cmdlets. For the snap-in to work in an x64 system, you need to register the dynamic link library with the 64-bit .NET framework by running the following command from an elevated command prompt:

C:\windows\microsoft.net\framework64\v2.0.50727\installutil.exe "c:\program files

After running this command, you should receive a message stating the commit phase was successful. 

If you use snapshots, you will also need the XenServer Snapshots snap-in. Make sure to add it to your PowerShell profile and don't forget to do a Connect-Xenserver command to start your sessions. Without it, PowerShell will spew error messages.

Find a XenServer guest using a MAC address

To determine a VM from its MAC address, you must obtain the object property for the Virtual InterFace (VIF) as shown below:

$vif = get-xenserver:VIF | ? { $_.MAC -match "ce:e2:b7:56:85:7f"};(Get-XenServer:VIF.VM -VIF

Applying the VIF property to the Get-Xenserver cmdlet performs a direct search for the MAC address of the virtual interface. The following command shows how to retrieve the VM information for the selected UUID (Universal Unique Identifier). Use that information to replace the VIF property. Simply changing the property allows you to retrieve, manage and correlate different results based on the property value.

Get-XenServer:VM -properties @{ uuid='$uuid' }

The Get-XenServer cmdlets boast an elaborate list of available properties, including Role, Pool, Secret, Sessions and Bond. Run a get-help Get-XenServer command to see all available properties and create your own query quickly and easily. 

More resources on PowerShell cmdlets

Using SCVMM PowerShell cmdlets to customize Hyper-V live migrations

How to write reusable PowerShell scripts for Exchange Server

Overcoming Hyper-V Live Migration limitations with PowerShell cmdlets

Looking beyond the Get-XenServer cmdlet

There are several other cmdlets in addition to the frequently used Get-XenServer cmdlet. You have the ability to use functions of XenServer, such as Create, Add, Destroy, Revoke, Set and Remove.

To view a list of available XenServer cmdlets and their properties, run a Get-Command *xen* from the PowerShell prompt.

Here are a few advanced scripts I've found that show the inner-workings of the XenServer cmdlets. This advanced script from blogger Maikel Gadder offers some great examples of how variables use and store properties.


# Xenserver-UpdateScript 
# V 0.9.2
# 20.07.2012
# written by Maikel Gaedker ([email protected])
# Updates XenServer with all patches available within a defined path
# Requirements: PowerShell v2.0; XenServerPSSnapIn
Import-Module XenServerPSSnapIn

$server = read-host "Enter XenServer to patch" # Enter XenServer Hostname or IP-Address when promted
$SecureString = read-host "Enter root-password" -asSecureString
$password =  [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString))

# Path to folder with downloaded XenServerpatches
# Only have required patches within these folder
$updatepath = "\\Fileserver\Shared_Folder\xs_updates" # Change to whatever your folder is

#Start Script

Connect-XenServer -server $server -UserName root -Password $password
write-host "$server will be patched; running VMs will be shut down" -foregroundcolor "green"
write-host "======================================================="
Get-XenServer:VM | Where-Object { $_.is_a_template-eq $false-and $_.is_control_domain-eq 
$false} | foreach-object {Invoke-XenServer:VM.CleanShutdown -RunAsync -vm $_.name_label}

foreach ($update in Get-ChildItem $updatepath)
write-host "Patch: $update will be prepared" -foregroundcolor "green"
Invoke-XenServer:Host.Disable -Host $server
Invoke-XenServer:Host.Reboot -Host $server
write-host "Server will be rebooted" -foregroundcolor "green"
start-sleep -s 300 # test if this time could be shorten for yor Xen Host
Connect-XenServer -server $server -UserName root -Password $password
write-host "$update will be uploaded" -foregroundcolor "green"
xe.exe -s $server -u root -pw $password patch-upload file-name=$updatepath\$update | out-file $server"_uuid.txt"
$uuid_patch = get-content .\$server"_uuid.txt"
write-host "$update will be installed" -foregroundcolor "green"
xe.exe -s $server -u root -pw $password patch-pool-apply uuid=$uuid_patch
write-host "$server was updated with patch: $update" -foregroundcolor "green"
write-host "======================================================="
write-host "$server was updated with all required patches; one last reboot" -foregroundcolor "yellow" Invoke-XenServer:Host.Disable -Host $server
Invoke-XenServer:Host.Reboot -Host $server
start-sleep -s 300 # test if this time could be shorten for your Xen Host
Connect-XenServer -server $server -UserName root -Password $password
Remove-Item .\$server"_uuid.txt"
write-host "VMs will be started" -foregroundcolor "green"
Get-XenServer:VM | Where-Object { $_.is_a_template-eq $false-and $_.is_control_domain-eq $false} | foreach-object {Invoke-XenServer:VM.Start -vm $_.name_label}

The following script by IT consultant and blogger Ingmar Verheij gives another good example. It 

More resources on Citrix XenServer

Citrix XenServer 'on the clock' as hypervisor wars heat up

Citrix XenServer storage: How it works and what can go wrong

allows users to connect to a XenServer VM's console via Remote Desktop Protocol (RDP). Verheij also wrote a script that allows a direct console connection to the VM, but RDP is much more efficient way to do this. 

Verheij also gives a good primer on how to use third-party applications in your PowerShell scripts, such as plink.exe, which he uses to invoke the command-line version of the SSH client PuTTY.

Finally, he demonstrates the ability to execute native OS or CLI commands within the script itself. In the section of the code that starts "Retrieve the IP of the VM," Verheij uses the xe vm-list command -- a XenServer CLI command -- to filter the properties of the VM.


# Name               :RDSXSConsole.ps1

# Description   : Connects to VM hosted on a XenServer hypervisor via Microsoft
Remote Desktop Client
# Author             : Ingmar Verheij - http://www.ingmarverheij.com/ # Version            : 1.0, 13 february 2012 # # Requires           : plink (a command-line interface to the puTTY back ends) #                          http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
# function StartProcess([String]$FileName, [String]$Arguments){     $process = New-Object "System.Diagnostics.Process"     $startinfo = New-Object "System.Diagnostics.ProcessStartInfo"     $startinfo.FileName = $FileName     $startinfo.Arguments = $arguments     $startinfo.UseShellExecute = $false
    $startinfo.RedirectStandardInput = $true
    $startinfo.RedirectStandardOutput = $true     $startinfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
    $process.StartInfo = $startinfo
    $temp = $process.start()     return $process }   #Region PrerequisiteCheck    #Check number of arguments    If ($args.count -lt 5)    {       Write-Host "Usage"       Write-Host "powershell.exe .\RDSConnect.ps1 (XenServerPoolMaster) (XenServerUsername) (XenServerPassword) (VMName) (Network ID) [CustomFieldName] [CustomFieldValue]"       Write-Host ""
      Write-Host "Example"
      Write-Host "powershell.exe .\RDSConnect.ps1 root Passw0rd WS01 0 STUDENT 1"
      Write-Host ""       Write-Host "Press any key to continue ..."
      $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
#Region Define variables and read
   $strExecutableMSTSC=((Get-Item "Env:WinDir").Value)+'\system32\mstsc.exe'    $strExecutablePLink=(Split-Path -parent $MyInvocation.MyCommand.Definition) + '\plink.exe'    #File paths    $strPathTemp=$Env:TEMP
   $strFileQueryNetworks ='QueryNetworks'
   #Script variables    $XenServerHost=$args[0]    $XenServerUsername=$args[1]    $XenServerPassword=$args[2]    $VirtualMachineName=$args[3]
   If ($args.count -ge 7) {
      $CustomFieldName=$args[5]               $CustomFieldValue=$args[6]    } else {          $CustomFieldName=""
         $CustomFieldValue=""    }    $strNICInterface=($VirtualMachineNetworkID)+'/ip: '    #Filter variables
   $strFilterVM='name-label="' + $VirtualMachineName+'"'
   IF ($CustomFieldName) {$strFilterVM+=' other-config:XenCenter.CustomFields.' + $CustomFieldName + '=' + $CustomFieldValue}

#EndRegion #Prevent rsa2 key fingerprint message #==================================== #The server's host key is not cached in the registry. You have no guarantee that the server is the computer you #think it is. #The server's rsa2 key fingerprint is: ssh-rsa 2048 7c:99:f3:31:38:ca:b7:b6:3b:21:53:55:ff:f3:76:1e #If you trust this host, enter "y" to add the key to PuTTY's cache and carry on connecting.
#If you want to carry on connecting just once, without adding the key to the cache, enter "n".
#If you do not trust this host, press Return to abandon the connection. # #Run plink and confirm rsa2 key fingerprint with yes
#--------------------------------------------------- $process = StartProcess $strExecutablePLink (' -l '+$XenServerUsername+' -pw '+$XenServerPassword+' '+$XenServerHost+' exit')
$process.StandardInput.WriteLine('y')   #Retrieve IP of VM #================= # #Create a script to query a XenServer and ask the networks of the VM #------------------------------------------------------------------- New-Item $strPathTemp -Name $strFileQueryNetworks -type file -Force  | Out-Null Add-Content ($strPathTemp + '\' + $strFileQueryNetworks) -Value ('xe vm-list '+$strFilterVM+' os-version:distro="windows" params=networks --minimal')
#Run the script on the specified XenServer
#----------------------------------------- $process = StartProcess $strExecutablePLink (' -l '+$XenServerUsername+' -pw '+$XenServerPassword+' '+$XenServerHost+' -m '+($strPathTemp + '\' + $strFileQueryNetworks))
$VMNetworks = $process.StandardOutput.ReadLine()
Remove-Item ($strPathTemp+'\'+$strFileQueryNetworks)
#Determine if the networks of the virtual machine can be found
#-------------------------------------------------------------- if(!$VMNetworks) { Write-Host "The virtual machine '"$VirtualMachineName"' could not be found." Write-Host ""    Write-Host "Press any key to continue ..."    $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
   break } else {   
   #Determine the IP address of the NIC can be found    foreach ($strVMNetwork in $VMNetworks.Split(";")) {       if ($strVMNetwork.Contains($strNICInterface)) {           $strVMIPaddress=$strVMNetwork.Substring($strVMNetwork.IndexOf($strNICInterface) + $strNICInterface.Length)       }    }
   #Determine if the IP address of the network ID can be found    #--------------------------------------------------------------    if(!$strVMIPaddress) {       Write-Host "The IP address of network '"$VirtualMachineNetworkID"' could not be found."       Write-Host ""       Write-Host "Press any key to continue ..."       $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")       break
   }    else {        Write-Host "The virtual machine '"$VirtualMachineName"' is connected via IP "$strVMIPaddress    }

#Start MSTSC to the VM
$processMSTSC=StartProcess $strExecutableMSTSC ('/v:'+$strVMIPaddress+' /f')

Lastly, on the Citrix blog, Ajene' Hall Barrett posted an extremely functional script (albeit elaborate) script that automates provisioning of virtual desktops. It includes variable references, Active Directory cmdlets, and a mix of XenServer and PVS (Provisioning Server) cmdlets. The full script is well-written and educational.

Advanced scripts further prove how many things you can automate and administer with the XenServer PowerShell cmdlets. And those capabilities should only expand and improve as Citrix evolves its toolset.

Dig Deeper on Citrix XenServer