Tuesday 12 November 2013

Mouse unavailable in Windows Server 2012 R2 on XenServer 6.2

After a fresh installation of Windows Server 2012 R2 on XenServer 6.2, the mouse became unavailable. Even with the latest patches available from Citrix (up to XS62E009) and the XenTools installed, still no mouse. It was available from Remote Desktop, but not really convenient.

After some research, I checked in the Device Manager and found an issue with the PCI to USB Universal Host Controller.

I uninstalled it and went to Action, Scan for hardware changes...

The PCI to USB Universal Host Controller was successfully recreated, and a USB Root Hub has also been successfully added.



The mouse is now available, and no reboot is required.

This issue might come back; it seems to be a known issue with Windows Server 2012 R2 and Windows 8.1. See this post on Citrix Forums.


Monday 11 November 2013

How to automate Citrix XenServer PowerShell scripts

Using the XenServer PowerShell cmdlets, it's now easy to automate tasks in XenServer using PowerShell scripts.

This script is based on XenServer 6.2 PSSnapIn, but with few changes, you can adapt to previous version. Cmdlets have different names from previous version (for example, Get-XenServer:VM is now Get-XenVM...).

First, you need to download the XenServer SDK from Citrix website, and the install the XenServerPSSnapIn.

First thing you have to do before you can call any method is to load the PSSnapIn. The command to do it is:
Add-PSSnapIn XenServerPSSnapIn

If you use it in a script, you need to ensure that it's not throwing an error if it's already loaded and terminating your script, so we check before adding:
if ( (Get-PSSnapIn -Name "XenServerPSSnapIn" -ErrorAction SilentlyContinue) -eq $Null ) {Add-PSSnapIn XenServerPSSnapIn}

Then, you need to declare the XenServer host you're connecting to; you need to point at the poolmaster.

So, below you create an array in case you have several pools to look after:
[array]$xenserver_poolmaster = @("mypoolmaster1","mypoolmaster2","mypoolmaster3")

Next, we'll make a loop through the array (% stand for "foreach"):
# Loop through list of hosts (poolmaster)
$xenserver_poolmaster | % {
  ... do things ...
}

To connect, you need to authenticate. You could mention the password in clear text, but it's safer to use a stored encrypted password as described in the following post.

To connect to a XenServer host, we'll use the following command line:
Connect-XenServer -Server $_ -Creds $xenserver_credential -SetDefaultSession

Once connected, as an example, we'll retrieve the list of VMs:
Get-XenVM | ? {$_.is_a_snapshot -eq $false -and $_.is_a_template -eq $false -and $_.is_control_domain -eq $false -and $_.power_state -eq 'running'} | Select-Object name_label

Then, we'll disconnect from the pool:
Get-XenSession -Server $_ | Disconnect-XenServer

So, see below the complete script:
[array]$xenserver_poolmaster = @("poolmaster1","poolmaster2")
[string]$xenserver_username = "root"
[string]$xenserver_credential_path = "c:\temp\xenserver_pool.pwd"

# If Password file does not exist, create it
if ((Test-Path -Path $xenserver_credential_path) -eq $False) {
    (Get-Credential).Password | ConvertFrom-SecureString | Out-File $xenserver_credential_path
}

# Read the password
$xenserver_password = cat $xenserver_credential_path | ConvertTo-SecureString

# Create the PSCredential Object
$xenserver_credential = New-Object -Typename System.Management.Automation.PSCredential -ArgumentList $xenserver_username, $xenserver_password

# Import the XenServer PSSnapIn
if ( (Get-PSSnapIn -Name "XenServerPSSnapIn" -ErrorAction SilentlyContinue) -eq $Null ) {Add-PSSnapIn XenServerPSSnapIn}

# Loop through list of hosts (poolmaster)
$xenserver_poolmaster | % {

  # Connect to XenServer pool
  Connect-XenServer -Server $_ -Creds $xenserver_credential -SetDefaultSession

  # Retrieve the information
  Get-XenVM | ? {$_.is_a_snapshot -eq $false -and $_.is_a_template -eq $false -and $_.is_control_domain -eq $false -and $_.power_state -eq 'running'} | Select-Object name_label

  # Disconnect from the XenServer pool
  Get-XenSession -Server $_ | Disconnect-XenServer

}

How to safely store a password in PowerShell

Usually, one of the main challenges when you want to automate tasks using PowerShell scripts, is to use authentication without showing the passwords in clear text. Even if you sign your scripts, the password remains in clear text.

You can use the Get-Credential cmdlet to prompt for username and password which avoid saving the password inside the script, but it means you'll not be able to run the script unattended.

However, what you can do is to use Get-Credential the first time to store the password encrypted somewhere, and call it from that file everytime the script runs. Editing the file will not reveal the password as it's encrypted, and to avoid anyone to use it, you could use NTFS permissions to ensure the file is only readable by expected administrators.

So, here is how you could do it:

# Set the file path variable (extension is not important)
[string]$credential_filepath = "c:\credential.pwd"

# Check if the file exists; if not, create it (should be used once)
if ((Test-Path -Path $credential_filepath ) -eq $False) {
 (Get-Credential).Password | ConvertFrom-SecureString | Out-File $credential_filepath
}

# Read the password
$my_stored_password = cat $credential_filepath | ConvertTo-SecureString

# Add it back to a credential object
$cred = New-Object -Typename System.Management.Automation.PSCredential -ArgumentList "username", $my_stored_password

So now, you can use it with any cmdlet where pscredential objects are used like Get-WmiObject.

It's not a highly secure solution but it's definitely a good balance between security and efficiency.

How to know on which XenServer host VMs are running


Load-balancing and High Availability are great XenServer features, however, for various reasons, you might want to check on which host which VM is running, and to have the ability to automate the task.

The following powershell script has been created for the XenServer 6.2, using the following XenServerPSSnapin: XenServerPSSnapIn-6.2.0-1.msi

This script does work the same way with previous versions but the cmdlets names changed (e.g.: Get-XenVM was Get-XenServer:VM...).

# Import the XenServer PSSnapIn
Add-PSSnapIn XenServerPSSnapIn

# Connect to the XenServer pool
Connect-XenServer -Server "IP of the poolmaster" -Username "root" -Password "password" -SetDefaultSession

# Retrieve the information
Get-XenVM | ? {$_.is_a_snapshot -eq $false -and $_.is_a_template -eq $false -and $_.is_control_domain -eq $false -and $_.power_state -eq 'running'} | Select-Object name_label, @{Name="hostname";Expression={(Get-XenHost -ref $_.resident_on).hostname}}

# Disconnect from the XenServer pool
Get-XenSession -Server "IP of the poolmaster" | Disconnect-XenServer