Citrix Provisioning Services 5.1 PowerShell Interface, Part III

Citrix Provisioning Services 5.1 PowerShell Interface, Part III

Update 2016-04-29: as from Provisioning Services 7.7, the PVS API provides a standard object-oriented PowerShell interface!

Hello again and welcome to the third part of my blog post series dealing with McliPSSnapIn – the PowerShell SnapIn to automate the Citrix Provisioning Services (PVS). Hope you enjoyed the first two parts and played with the McliPSSnapIn cmdlets meanwhile. This time you’ll learn how to handle the output of the Mcli-Get cmdlet meaning how to convert its structured text to an object (or an array of objects).

For example, suppose you want to display all vDisks sorted by size in descending order. By intuition, Mcli-Get DiskInfo and Sort-Object seem well-suited for this job get done.

Worse luck! This will end up in a mess (which I don’t want to show here). As formerly mentioned, McliPSSnapIn‘s cmdlets don’t deliver objects but rather text information just in the fashion of a legacy console utility. This is not much fun.

Since PowerShell supports the creation of custom objects you can convert Mcli-Get‘s output to your own “homebrew” object, strictly speaking to a Device, Disk, Site, Store, Farm, whatever PVS object. Look at this working solution:

Compared to the task to create an object and to assign property names with values to that object it is actually more challenging to parse the text-based information in order to identify the information related to each single object.

You’re not scared now, are you? 😉 Let’s take one thing at a time – according to Louis X divide et impera strategy.

First, let’s analyze the text returned by Mcli-Get DiskInfo on my test system:

The cmdlet returned the “properties” of three vDisks. The text is structured nicely in order to support human readability:

  • The output begins with a short summary followed by an information block for each returned record (object).
  • Each information block is introduced with “Record #nnn” where nnn stands for a counter
  • Furthermore empty lines separate the information blocks from each other.
  • The lines that contain the actual data for the records (objects) are indented “name: value” pairs like “diskSize: 41940702720”

Based on this research findings you’re able design an algorithm as stated above to convert the cmdlet’s output to an array of objects.

The Power Of “switch -regex” Unveiled

Naturally you need to process the returned text data in a loop. At first glance it seems perfectly possible to use a foreach loop as follows:

Inside each run it is important to distinguish between three cases:

  • A new information block begins (initiated by “Record #nnn“)
  • Information for the current record (object) in the form of “name: value
  • Superfluous information (as for instance the summary)

I consider this a classic case for a switch statement with the -regex option in order to identify a match with “Record #nnn” and a match with “name: value“.

You know what? switch is able to process a pipeline (an array of elements) itself, meaning you can forget foreach and let switch process Mcli-Get‘s output directly:

According PowerShell’s help, the switch statement’s -regex option “indicates that the match clause, if a string, is treated as a regex string.” So, you need two regex strings, one to identify a “Record #nnn” line and one to identify a “name: value” pair. I will explain my regex statements below.

This regex string matches “Record #nnn“: ^Record\s#\d+$

Element Description
^ Matches the beginning characters
Record Matches “Record”
\s Matches any single white-space character
# Matches “#”
\d Matches any decimal digit
+ Matches repeating instances of the preceding characters
$ Matches the end characters

This regex string matches “name: value“: ^\s{2}(?\w+):\s(?.*)

Element Description
^ Matches the beginning characters
\s{2} Matches exactly two white-space characters
(?<Name>\w+) Matches any word character until the next non-word character and assign the result to $Matches.Value
: Matches “:”
\s Matches any single white-space characters
(?<Value>.*) Matches the rest of the line and assign the result to $Matches.Value

And what is $Matches? PowerShell places resulting matches automatically in the $Matches hashtable where $Matches[0] always holds the entire match. Furthermore, PowerShell allows to specify (optionally named) capture groups inside a regex string. These captures will be assigned to separate elements of the $Matches hashtable, either numbered or named. The example below shows what I’m trying to explain:

This is so cool! Did I already mention that I love PowerShell?

How To Avoid Flattening Of Arrays?

I need to tell you that the return value of the above-stated Get-DiskInfo function messed me around a while.

The function should always return an array regardless of the number of objects found by Mcli-Get. The problem I was running into was that the function didn’t returned an array when the object count was 1. Instead it returned the object directly.

In order to avoid that PowerShell unrolls or flattens the array when it would contain only one element I used the comma operator to force the function to return the array as is:

Ah, I’ve missed to show the Get-DiskInfo function in action:

The Get-DiskInfo function is a very basic example for creating custom objects in PowerShell and therefore should considered to be a kick-start.

I hope it inspired you to dive deeper at Christmas time.