In the last could of “change you should make” posts I’ve talked about a couple of things which turn  Functions from being the poor-relation of compiled Cmdlets (as they were in PowerShell V1) to first class citizens, under V2. Originally the term “Script Cmdlets” was used but now we call them “Advanced functions”. This is quite an important psychological difference because writing a cmdlet – even a “script cmdlet”  sounds like difficult, real, programming. On the other hand an advanced function sounds like a function with some extra bits bolted on and nowhere near as daunting.

In V2 there is a new version of the Tab-Expansion function which completes names of functions and fills in parameters , and that doesn’t need any change to the code. In part 2 of this “Change you should make” series I talked about the better discover which comes from putting your functions into modules – simply type get-command <module-Name> and you get the list. And In part 1 I talked about the fact that we get support for the important common parameters –whatif, and –confirm for example. So we can find script-cmdlets advanced functions, and we can test to see if they are going to trash the system before we run them for real. What’s the one great thing about PowerShell that’s missing ? Consistent help everywhere!

In V2 you can put in a comment which actually defines help information, like this:

Filter Get-VMThumbnail
{ <#

.SYNOPSIS
       Creates a JPG image of a running VM

     .PARAMETER VM
         The Virtual Machine
     .PARAMETER width
         The width of the Image in Pixels (default 800)

    .PARAMETER Height
        The Height of the Image in Pixels (default 600)

    .PARAMETER Path
        The path to save the image to, if no name is specified the VM name is used.
If no directory is included the current one is used

    .EXAMPLE
        Get-VMJPEG core
        Gets a 800x600 jpeg for the machine named core,
and writes it as core.jpg in the current folder.
.EXAMPLE
        While ($true) { Get-VMJPEG -vm "core" -w 640 -h 480 `
-path ((get-date).toLongTimeString().replace(":","-") + ".JPG")
{Sleep -Seconds 10}
       Creates a loop which continues until interrupted; in the loop creates an image of the
VM “Core” with a name based on the current time, then waits 10 seconds and repeats.

#>

 

This is all very fine and good – and there are other fields which you can read about in the on-line help. As far as I can tell there are just two things wrong with this,

  1. It needs a fair amount of processing to extract the help into a document as the basis of a manual.
  2. It adds a lot of bulk to a script – in fact most of my functions will be shorter than their help, I don’t think this is truly harmful, but I like my scripts compact.

image Fortunately both of these are solved by using external  help files – which are in XML format. The help declaration is simple enough.

Function Get-VMThumbnail
{# .ExternalHelp  MAML-VM.XML

The XML schema is known as MAML and isn’t the nicest thing I’ve ever worked with….

A little while ago I was filling in my year end review and inside Microsoft we do this using an InfoPath form. I could write all I knew about infopath on the back of a postage stamp. You fill in forms which come out as XML. Could InfoPath give me an easier way to get MAML files ? As it turns out the answer was “yes”, and I’ve learnt enough infopath to make half a blog post.  It turns out that InfoPath can read in an existing data file to deduce the the XML structure you want to have as the result of filling in the form: once it has the structure you can drag the document elements around to make a form.

It’s not the most beautiful bit of forms design ever – and the XML does need a change to move between editing in infoPath and using for PowerShell help. But it compared with putting the XML together in notepad … well, there is no comparison. I’ve attached the InfoPath form for those who want it. Filling it in is pretty much self explanatory, with the exception of Parameter sets. Each Parameter is entered in its own right and at least one (default) parameter set is defined. The set names are actually displayed as the command when the help is displayed so the set name needs to be the command name for every set.

I could script the change required, but I don’t seem to be able to manage it in infopath , at the top of the file there is an opening <HelpItems> XML tag. To work as Powershell help this needs to contain XMLNS=”http://msh”  Schema=”MAML”. InfoPath considers the file to be invalid if the first of these is present, so you need to take the file out to edit it.

One final warning when you’re developing the XML help, once PowerShell has loaded the XML file it doesn’t seem to want to unload it so you have to start another instance of the shell –using the graphical ISE version of Powershell I found just press control T to get a new instance of the shell in its own tab.