Function to Bulk-Register PowerShell Snap-Ins

  • 0

Function to Bulk-Register PowerShell Snap-Ins

I wrote the PowerShell function below, Register-PSSnapin, to facilitate the usage of the InstallUtil.exe program in order to register a series of PowerShell snap-ins. Since this utility isn’t located in the “normal” command path, you have to find it in the .NET Framework’s directory. Or, with my function you just don’t care 😉

Side note: in PowerShell 2.0 the concept of snap-ins is substantially replaced by binary modules. Apart from the fact that the core of PowerShell 2.0 is delivered as snap-ins, many software vendors still provide a PowerShell snap-in to allow for command-line based administration and automation. (For example the latest release of Citrix Provisioning Services 6.0 ships a PowerShell Snap-in.)


  • 3

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.


  • 0

Citrix Provisioning Services 5.1 PowerShell Interface, Part II

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

Welcome to the second part of my series of blog posts dealing with the PowerShell SnapIn called McliPSSnapIn that Citrix provides as an programming interface for the Citrix Provisioning Services (PVS).

The first part only covered the installation/registration of the SnapIn and furthermore it introduced a function called Test-PSSnapIn to add the SnapIn to the current PowerShell session (respectively to test if it could added successfully).

This time I want to point out more clearly how the McliPSSnapIn‘s cmdlets vary from PowerShell standard. It’s just that the SnapIn has its own standard after all. A general approach to test if a given PVS object exists (like a vDisk, Device, or Collection) will top off part II.

McliPSSnapIn Standards

As mentioned in the prologue of part I, the cmdlets of McliPSSnapIn are not 100% PowerShell-compliant meaning that…

  • the cmdlet names don’t meet PowerShell’s “Verb-Noun” naming schema,
  • the cmdlet’s syntax doesn’t match with PowerShell’s standards, and
  • the cmdlets don’t return objects but arrays of pure text elements.

Instead, the McliPSSnapIn introduces its own standards – anything is better than nothing.

Cmdlet Naming

Overall there are only nine cmdlets or “command types” (Citrix-terminology):

Mcli-Add, Mcli-Delete, Mcli-Get, Mcli-Help, Mcli-Info, Mcli-Run, Mcli-RunWithReturn, Mcli-Set, and Mcli-SetList

You see, the cmdlet naming doesn’t follow PowerShell’s “Verb-Noun” principle but rather its own standard that is “Mcli-Verb” or “Mcli-Action” (according Citrix-terminology). Ah, did I already mention that Mcli stands for Management Command Line Interface?

Cmdlet Syntax

No worries! I won’t write down a boring command reference now. If you need a reference look at Citrix’ PVS Programmer’s Guide, and there’s the Mcli-Help cmdlet by the way. This section just outlines the things in common concerning the syntax of all Mcli cmdlets.

Mcli-Help left out, the general syntax may be summarized as follows:

Basically, in terms of PowerShell standard you can take “Action” for “Verb” and “ObjectType” for “Noun” – not so bad after all.

Actions

Besides “Help” there are eight Actions:

Mcli-Add Add an object and return the object’s unique Id
Mcli-Delete Remove an object
Mcli-Get Get one or more objects and return according information as array of strings
Mcli-Info Get information about objects and return them as array of strings
Mcli-Run Run an action without return value
Mcli-RunWithReturn Run an action and return information as array of strings.
Mcli-Set Set property values for one or more objects without return value
Mcli-SetList Set a list of property values for an object without return value

ObjectTypes

Depending on the action there are more or less object types. To name but the most common only:

Collection, Device, DiskLocator, Server, Site, and Store

But as said before there are many more.

Arguments

There are four types of arguments indicated by “-f”, “-r”, “-p”, and “-s”:

-f Indicates a field (object property name) or a list of fields, separated by comma, to be returned.
-p Indicates a single or a comma-separated list of name=value pair parameters to identify an object.
-r Indicates a single or a comma-separated list of name=value pair records to be set on an object.
-s Indicates a field to sort on.

Syntax Examples

Some examples dealing with the Device object will certainly help to to clarify so much theory:

These samples are taken from the PVS Programmer’s Guide. I don’t know if they really work but it is good enough to show how the Mcli cmdlet syntax concept differs from PowerShell standards.

Cmdlet Return Values

The real annoyance about the Mcli SnapIn is the fact that their cmdlets return simple text, more precisely: arrays of strings. Practically the return values don’t differ from the return values of an external console utility like ipconfig.exe.

For example, it is well established that PowerShell’s most awesome feature is the Object Pipeline and it is a pity that you can’t use this extremely resourceful feature with the Mcli cmdlets. (Well, you can use the Object Pipeline in order to apply it to the string objects the cmdlets return though.)

Consequently, you need to inspect returning data using string operation methods like Substring() or Trim(). And PowerShell wouldn’t be PowerShell without its great Regular Expression support that helps tokenize strings to identify requested data (which is an easy task once you have played with regular expressions and understand how they’re working).

If you’re willing to put more effort in development time you can write your own PowerShell function library to encapsulate the Mcli cmdlet’s functionality completely and create your homebrew Collection, Device, Store, and Site objects with scripted methods. Maybe – it depends on your comments, folks! – I will provide some examples how to create your own object in a future part of this series about the PVS’ PowerShell SnapIn.

Hey, wake up! We’re back in example mode. 😉 The cmdlet Mcli-Add returns a unique Id of the object added. Look at this example output:

So, besides the interesting data (meaning the Add succeeded and the resultId) there’s virtually gross information. Now, let’s inspect the return value stored in the $rv variable…

You see, Mcli-Add didn’t return a Device object with all its properties and methods. Actually, it returned an array of three strings (the first is empty). Therefore, if you want to process the new Device – let’s say you need to set a property value (Citrix-terminology: record value) – you can’t just do it the way you might expect by typing this:

No, instead you need to fire up another cmdlet, Mcli-Set, to apply the desired property value:

So far, so good. The cmdlets work, but hopefully you’re getting the picture now why I consider the concept how Mcli works annoying. It’s not that ingenious PowerShell way, it’s just old school (meaning text based) scripting.

Test Object Existence

In this chapter I want to share a set of functions that test for existence of a given object, let’s say a Device.

For example the function PVS\Test-Device returns either True or False depending on the text information returned by Mcli-RunWithReturn. Let’s take a look at the function first:

Actually, the function returns True or False based on a regular expression comparison applied to the third line of Mcli-RunWithReturn‘s text output. What matters is that the text of the third line matches the character “1”, meaning if there’s no “1” the given Device name doesn’t exist. Let’s have a look at the Mcli-RunWithReturn‘s complete output:

You see, Mcli-RunWithReturn‘s output differs only at the position where the cmdlet displays the return value. To prove that the function is working:

Taking the PVS\Test-Device function as a reference it is easy to build more functions to test for example the existence of a Site, Store, or Disk:

The PVS\Test-Disk function needs some more parameters due to the fact that Mcli-RunWithReturn needs also the name of the Site and the Store to determine if a given Device name there exists.

You’ve reached the end of part II. Next part I will dive deeper into scripting tasks finally. So stay tuned and don’t miss the chance to write comments meanwhile…


  • 0

Citrix Provisioning Services 5.1 PowerShell Interface, Part I

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

With this post, I want to share some functions to automate Citrix Provisioning Services (PVS) 5.1. But let me tell a short story first…

Prologue

One of these days, I had to implement some PVS functionality into Solution4 at a customer. Only knowing by hearsay that a PowerShell programming interface or PowerShell SnapIn to automate PVS 5.1 exists, first I considered that task pretty easy. Some days later, during getting prepared for the job, the initial thrill of anticipation steadily changed into a feeling of disillusion. Why? I will tell you why.

To put it mildly, the PowerShell SnapIn for PVS 5.1 – baptized McliPSSnapIn – takes some getting used to, meaning it doesn’t follow any common PowerShell standards like the naming convention or the “syntax design” of cmdlets (to name the least worse first). The data returned from McliPSSnapIn‘s cmdlets is – simple text! For example you won’t get an array of vDisk objects from Mcli-Get DiskLocator as one might expect with reason. Instead Mcli-Get returns an array of pure text lines without any deeper relation to the information. Thus you need to parse returning data just the way if they would coming from an external console utility – Whoop! Welcome to Split(), Substring(), Trim(), and their friends, not forgetting Regular Expressions that can make your day if you know how to use them.

Since McliPSSnapIn‘s cmdlets are working I won’t claim that this SnapIn is load of crap. Nevertheless it’s annoying and I hope that Citrix will provide a PowerShell-compliant interface for PVS better late than sorry. (Yes, They Can! For example Citrix yet has done a good job on developing a PowerShell programming interface to automate Citrix XenApp – the Citrix XenApp Commands.)

First of all, you should get a copy of the Citrix Provisioning Services 5.1, 5.1 SP1 PowerShell Programmer’s Guide that is published in the Citrix Knowledge Center Article CTX121334. Don’t expect too much from this PDF document, it contains 150+ pages information though. The guide mainly consists of highly purified syntax help and much repeated information but it lacks substance like detailed descriptions. It is worth to use as command reference anyways.

Enough talk. (Did I already mention that I don’t like to talk?) Let’s have a closer look at McliPSSnapIn now.

Preparation

I believe you’re reading this article because you have Citrix Provisioning Services 5.1 (SP1) up and running and now need to realize some automation tasks in Windows PowerShell. Already mentioned previously, the essential requirement to automate Citrix PVS with PowerShell is the McliPSSnapIn PowerShell SnapIn.

McliPSSnapIn is a dll file and part of the Provisioning Services Console. Unsurprisingly you find the file in the PVS Console’s installation directory that is normally %ProgramFiles%\Citrix\Provisioning Services Console.

Before you can add the SnapIn to a PowerShell session with Add-PSSnapIn it needs first to be registered in PowerShell. This is a one-time task. As stated correctly in the PVS Programmer’s Guide, this can be done by running the .NET Framework’s utility InstallUtil.exe – see page 7, I don’t want to crib 😉

How can I find out if the McliPSSnapIn is added to the current PowerShell session?

Several ways exist to check if a PowerShell SnapIn is added to the current PowerShell session. My way is a tiny little bit brute force since it simply tries to add the SnapIn without any previous steps:

First, my function tries to add the SnapIn while suppressing possible error messages by setting the according ErrorAction parameter value (SilentlyContinue). Indeed an error may occur due to the fact that either the SnapIn was added already or the SnapIn is not present on the system. Secondly the function tries to identify the given PSSnapIn using the Get-PSSnapIncmdlet.

If the SnapIn is added (either just now or previously) the function will return “True”, apart from that it returns “False” if the SnapIn is not installed or registered. Beyond that (in case of return value “False”) you can dredge up the suppressed error message using the standard PowerShell variable $Error as follows:

The $Error variable is PowerShell’s error stack. It saves the details of the errors that occurred recently (I don’t know how many). Each error is an array element, and the most recent error details can be found in the first element of the array, that is $Error[0]. The Exception property of the error object provides the error message.

Ok, this is end of the first part. I need to go to bed now 😉 More parts will follow soon. Good night and don’t miss the chance to write comments meanwhile…