PowerShell and Named Parameters

PowerShell makes for easy named parameter creation (better than VB stuff, and much more better than DOS stuff). This was something that I asked in the last PowerShell training class I had, but the instructor didn’t quite get what I was asking (above his head, probably — laughs).

To utilize parameters (and named parameters), you can use “param” in your script. So, you can declare some parameter in the script such as:

param([string]$strClusterName = "MyDefaultClusterName")

This does a couple of things. 1) Creates a named parameter “strClusterName” of type “string”, and 2) sets a default value for it of “MyDefaultClusterName”. You could exclude the setting of a default, and just have a named parameter. Then you could test for a value, for null, or whatever you felt like. With that default value in there, if someone calls that script without passing a parameter, it uses the value you set as default (if that wasn’t clear).

So, when calling your script, you could pass a parameter like:

PS C:> myScriptsmegaScript.ps1 MyOtherClusterName

Or, to be explicit and avoid errors due to mismatched positional parameters, you could pass a named parameter to the script like so:

PS C:> myScriptsmegaScript.ps1 ?strClusterName MyOtherClusterName

Using the explicit parameter name when the script only accepts one parameter might seem a bit unnecessary at first glance, but a few months down the road when you’re looking at an example usage of your script and see that parameter name, you know what the hell that parameter is?

So, the name of the variable that you create in the param section of code is the name of the parameter to be used at run time. This holds true for functions, too. If you had a function like:

function dRdp() {
    mstsc.exe /v:$strServerName

then, like in the earlier example you could call it with a named parameter as such:

PS C:> dRdp -strServerName myServer010

Here, leaving off the parameter name yields the same results — the parameter is then considered a “positional” parameter. But, let’s say that you wanted to handle other optional parameters. Now the function is like:

function dRdp_v2() {
    mstsc.exe /v:$strServerName $args[0] $args[1]

When calling this function with no named parameters like so:

PS C:> dRdp_v2 myServer010 3389

the first parameter passed is used for the explicit param “$strServerName“, and the second parameter “3389” is returned by “$args[0]” as such:

$strServerName: myServer010
$args[0]: 3389

Not necessarily what you’d expect for the $args[] array. Notice here that the named parameter specified in the function definition gets set to the first positional parameter, and the rest of the positional parameters are placed into the $args[] array, starting at index 0.

Now, if you were to call the function with a named parameter, regardless of the position, the parameter in the function gets set to the passed named value, and the rest of the non-named parameters populate the $args[] array. So, calling the function in the following ways gives consistent results:

PS C:> dRdp_v2 -strServerName myServer010 3389
PS C:> dRdp_v2 3389 -strServerName myServer010

A few other notes:
There is another way to make parameters for a function: you can also define parameters within the parenthesis in the function definition. This is a bit more natural for people who are accustomed to programming languages in which this is how parameters are specified. For example, one can define the parameter in the function “dRdp_v2” as follows:

function dRdp_v2([string]$strServerName) {
    mstsc.exe /v:$strServerName $args[0] $args[1]

I am partial to this format, mainly because of past exposure, but also because of the increased typing efficiency/tightness of code.

Along the same lines of efficiency are named parameter abbreviations. When using named parameters in a function call or in calling a script, you can truncate the parameter name as much as desired, so long as the resultant name is still unique among the possible parameters. That is to say, the shortest non-ambiguous parameter name works. So, if you made a function with three parameters, “$serverName_str“, “$securePort_int” and “$nonSecurePort_int“, you could call the function as follows, and all would work:

PS C:> myFn -serverName_str svr010 -securePort_int 443 -nonSecurePort_int 665
PS C:> myFn -server svr010 -secure 443 -nonSec 665
PS C:> myFn -ser svr010 -sec 443 -n 665

And, the follow example does not work, as the first named parameter used, “-s“, is ambiguous:

## DOES NOT WORK -- the "-s" is ambiguous
PS C:> myFn -s svr010 -secure 443 -n 665

There is at least some help available via PowerShell. The only place I’ve seen it, though, is:

PS C:> Get-Help -Full about_function

So, now named parameters are going to rule the world.


VMware VI Toolkit (for Windows) — new Functions

What? Two posts? Well, as previously mentioned, the final 1.0 version of the VMware VI Toolkit (for Windows) came out 25 Jul 2008. I was excited to see that it fixed the issue of connecting to VMware Server 2 RC1 (released at the start of July 2008), where “Get-VIServer” commands failed from the beta 1.0 Toolkit.

So, in looking around at the new install of the VI Toolkit, I inspected the file that the Toolkit shortcut calls on startup, “Initialize-VIToolkitEnvironment.ps1” (found in Scripts). Huh — a few new aliases and a couple of new functions. “Get-VIServer“, “Get-VC“, and “Get-ESX” are all now aliases for the new cmdlet “Connect-VIServer“. The new functions are “New-DatastoreDrive” and “New-VIInventoryDrive“.

As described in the VI Toolkit’s Administrator’s Guide (PDF), these new functions seem quite tasty. For example, to create a new PowerShell PSDrive that corresponds to a given DataStore in your VMware environment, you could issue the commands:

Connect-VIServer virtualcenterserver.domain.com
New-DatastoreDrive "dsDrive" (Get-Datastore daterstore01)

where real names are entered for the VirtualCenter server (or VMware host) and for the Datastore. Now what? Well, you can “cd” (alias for “Set-Location“) into the newly created DatastoreDrive “dsDrive”. Yeah, that’s navigating the Datastore to which you connected — without need of using the Datastore browser in the VI Client, and without need to SSH to a host. Sweet. As the Admin Guide states, “The Datastore Provider (VimDatastore) is designed to provide access to the contents of one or more datastores.”

Then there’s the Inventory Provider (VimInventory): “…designed to expose a raw inventory view of the inventory items from a server. It enables interactive navigation and file-style management of the VMware Infrastructure inventory.” And, this can be achieved by doing something like:

Connect-VIServer virtualcenterserver.domain.com
New-VIInventoryDrive -Name "viInv" -Location (Get-Folder -NoRecursion)

You can then act on the inventory objects with the standard cmdlets. For example:

cd viInv:ha-datacentersomeFoldervm
dir *oldservers01* | Update-Tools

Of course, you would want to insert the proper path from your environment in the “cd” statement.? Or, you could just set your location to the root of the PSDrive and explore the path structure using standard “dir” or “Get-ChildItem” commands.? Yet another way to interact with VMware VI items using the VI Toolkit.

(And, in case you forgot, you can always use “Get-PSDrive” to see what PSDrives you currently have.)

New VMware VI Toolkit 1.0 fixes connectivity to Server 2 RC1

Well, the final 1.0 version of the VMware VI Toolkit (for Windows) came out 25 Jul 2008, without much fanfare. I had been using the 1.0 beta version for a few months, and things seemed good. I used it against ESX 3.0.1 and VirtualCenter 2.0 at work, and against beta versions of VMware Server 2.0 at home.

When VMware Server 2.0 Release Candidate 1 came out, I was quite unhappy that the VI Toolkit seemed to no longer work. I couldn’t even get Get-VIServer to connect to the local web services provided by VMware Server, though it had worked great for the last few months. Issuing the command:

Get-VIServer localhost -Port 8333

yielded nothing but an error. For weeks I tried different steps, from removing the VI Toolkit, to removing the Toolkit and Server, and reinstalling fresh. No dice.

I had pretty much given up, until I saw that v1.0 final of the Toolkit was available. After uninstalling the beta version, and installing the new version, jackpot. The “Get-VIServer” command mentioned above now worked again! Score. You might notice that the command is now an Alias for the new cmdlet “Connect-VIServer“. You might not. There is also a corresponding “Disconnect-VIServer“. Hurray.

Either way, VMware apparently changed something in Server RC1, and the new Toolkit is apparently updated as well to accommodate said change. I searched the web off and on for a couple of weeks. Hopefully this post will save someone some trouble.