Introduction



In this article I shall demonstrate the new XenServer PowerShell snap-in, using the simple example of “chained” VM starts: waiting for one VM to finish booting before starting the next.

The new SnapIn is available at http://community.citrix.com/cdn/xs/sdks.

In this example, we are using the XenServer Tools to detect when booting is complete: once they advertise the VM’s IP address, we assume that the VM is ready. Of course, you may want to make this more sophisticated, for example waiting for a domain controller to start before moving on. I’ll leave this to your imagination!

In the first screenshot, I’ve got XenCenter 5.0 talking to a XenServer 5.0 pool, XS-PS started afresh, and the script that runs this example, Start-VM.Wait.ps1. The PowerShell install is out-of-the-box, though I’ve already set the ExecutionPolicy to RemoteSigned.




Namespaces and Initialize-XenServer:Aliases



Firstly, a quick word about how we handle namespaces in XS-PS.

A lot of the Xen-API’s names are very generic; a cmdlet called “Create-Message” could clash with any number of things. With this in mind, XenServer’s cmdlets are named within a XenServer namespace, something like this:

Create-XenServer:VM
Destroy-XenServer:VM
Get-XenServer:VM
Get-XenServer:VM.NameLabel
Set-XenServer:VM.NameLabel
Invoke-XenServer:VM.Start

This is great for people who want to use XS-PS in a mixed environment, but it’s obviously a bit verbose for quick scripting, so we’ve added the ability to alias these full names to something shorter. In Start-VM.Wait’s process block, you can see the following call:

Initialize-XenServer:Aliases Start

This introduces a full set of aliases, so that we can now use names such as

Create-VM
Destroy-VM
Get-VM
Get-VM.NameLabel
Set-VM.NameLabel
Start-VM

These aliases are scoped within this script, so they won’t pollute the user’s environment. If you want, you can pass it a -Scope parameter, and have them put into an outer or global scope instead.

Initialize-XenServer:Aliases actually supports three styles of alias, so you can choose the style that best suits your environment, or you can stick with the full names if you prefer.

PS C:\Users\Ewan Mellor> Initialize-XenServer:Aliases
Invoke-Xen = Get-Xen:VM / Invoke-Xen:VM.Start
Invoke     = Get-VM / Invoke-VM.Start
Start      = Get-VM / Start-VM




Start-VM.Wait



Start-VM.Wait takes its VMs from the pipeline. It then processes them one at a time, like this:

  • If the VM record represents the control domain, or a template, then silently skip it.
  • If the VM is unstartable (because it’s already running, say), then log the fact, and skip it.
  • Otherwise, call Start-VM. This will block until the VM boot process begins.
  • Next, wait for up to five minutes for the VM to boot. We wait for the VM.guest_metrics field to be populated, and for an entry to appear in VM_guest_metrics.networks. Once there’s an entry here, we know that the XenServer Tools are ready, and the VM has an IP address configured (from DHCP, for example).
  • If polling this field fails after 5 minutes, then warn, and just move on to the next VM.


function Start-VM.Wait
{
    begin
    {
        $timeout = 5 * 60 * 1000
        Initialize-XenServer:Aliases Start
    }
    process
    {
        if ($_.is_a_template -or $_.is_control_domain)
        {
            return
        }
        if ($_.allowed_operations -notcontains "start")
        {
            Write-Warning("{0} cannot be started" -f $_.name_label)
            return
        }

        Write-Verbose("Starting {0}..." -f $_.name_label)
        Start-VM $_

        for ($count = 0; $count -le $timeout / 500; $count += 1)
        {
            $metrics = Get-VM.GuestMetrics $_
            if ($metrics -ne $null -and $metrics.networks.Count -gt 0)
            {
                Write-Verbose("VM {0} started" -f $_.name_label)
                return
            }
            Start-Sleep -m 500
        }

        Write-Warning("Timeout starting {0}" -f $_.name_label)
   }
}




Using it



Using this script is now very simple:

  1. Dot-source the script, to load the function.
  2. Set $VerbosePreference to “Continue”, just for this demo.
  3. Connect to your master server.
  4. Choose the VM’s that you want to start (in the example, all those tagged as “Production”).
  5. Pipe those VM’s into Start-VM.Wait.
  6. Watch the magic!
  7. Log out from your server afterwards.
PS> . .\Start-VM.Wait.ps1
PS> $VerbosePreference = "Continue"
PS> Connect-XenServer -url https://<servername>
PS> Get-XenServer:VM -Tags Production | Start-VM.Wait
...
PS> Disconnect-XenServer

This is a simple example, and no doubt you would want to tweak it to match your deployment, but I hope that it’s enough of an example for you to get started.



Downloads


Start-VM.Wait.ps1