$Null or Nothing?

When looking at a lot of PowerCLI scripts available I noticed that people tend to forget to validate their output. For example let’s look at the following piece of code:

$Vms = Get-VM

Although this command will return a collection in almost all cases, it can however return 3 different output types. It can return a collection, a scalar or no output at all. So when you simply assume that it returns a collection, you can go wrong on the next statements. Let’s try to clear things up and look at the following slightly different code:

$Vms = Get-VM
ForEach ($Vm in $Vms) {
  $Vm.GetType()
}

This simply returns the object type of every virtual machine. Now let’s alter the code a bit and notice the Where-Object cmd-let to filter the output of Get-VM:

$vms = Get-VM | Where-Object {$_.Name –eq "Hyper-V"}
ForEach ($Vm in $Vms) {
  $Vm.GetType()
}

This code will generate the following error, unless you’re a Microsoft masochist and really have a virtual machine named “Hyper-V”. ;-)

You cannot call a method on a null-valued expression.
At line:1 char:35
+ Foreach ($Vm in $Vms) {$Vm.GetType <<<< ()}
+ CategoryInfo : InvalidOperation: (GetType:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull

You probably wonder how that’s possible, because the first line will return nothing and therefore the ForEach statement shouldn’t do anything. Well not quite. The Get-VM part of the first line will return nothing and when assigning nothing to a variable in PowerShell, $Null is used to represent this empty set. So far so good, but there are some things you should know about PowerShell.

  1. $Null is treated as a scalar.
  2. The ForEach statement iterates a scalar once, because it is treated as an array with only one element, the scalar itself.

There you have it, because $Null is treated as a scalar, the ForEach statement iterates once and invoking the GetType() method on $Null will generate the aforementioned error. Therefore it is important that you always validate your output.

Now let’s look at a variation of this code:

ForEach ($Vm in (Get-VM | Where-Object {$_.Name –eq "Hyper-V"})) {
  $Vm.GetType()
}

Running this code won’t generate an error, because the Get-VM part is now inside the ForEach statement. (Get-VM | Where-Object {$_.Name –eq "Hyper-V"}) will still return nothing and the ForEach statement won’t run when nothing is returned. Spot the difference?

The problem is introduced by the use of the intermediate variable $Vms where nothing is replaced by $Null (a scalar meaning nothing)!

There are two ways to avoid this kind of error:

  1. Do not make use of the intermediate variable and put the entire statement inside the ForEach statement, which we just did in the last example.
    ForEach ($Vm in (Get-VM | Where-Object {$_.Name –eq "Hyper-V"})) {
      $Vm.GetType()
    }
  2. If the statement tends to grow rather large and putting it inside the ForEach statement renders the code unreadable, you could make use of the array subexpression to force the intermediate variable to be an array.
    $vms = @(Get-VM | Where-Object {$_.Name –eq "Hyper-V"})
    ForEach ($Vm in $Vms) {
      $Vm.GetType()
    }

So write your scripts wisely using one of these options and make them more robust and less error prone.

Also check out this Microsoft discussion about this subject:

https://connect.microsoft.com/feedback/ViewFeedback.aspx?FeedbackID=281908&SiteID=99

Related posts:

  1. List HBA WWPNs and LUNs using Powershell Tweet Lately I’m moving around my VMs and storage luns between my ESX clusters a lot to accomplish a complete redesign of my Virtual Infrastructure. At some point I got...
  2. How big is my VM? Tweet If you want to know the size of your vm, you probably first look at the size of the virtual disks in the vm’s settings, but there’s more to...
  3. PowerCLI 4.0 Update 1- Another leap forward Tweet Last week VMware released PowerCLI 4.0 Update1. According to the PowerCLI blog this new version contains over 60 new cmdlets as well as greatly improved performance. One great thing...
  4. Export and import customization profiles using Powershell Tweet One great thing in the automation of VM deployments is the use of customization profiles. These profiles are stored inside the vCenter Server database. However, when you loose the...
  5. Bulk change your ESX root password Tweet Have you ever been facing your security department demanding you to change your ESX root password? Well I did. At the current site there’s a strict security policy where...

1 Comment on “$Null or Nothing?”

  1. #1 Bouke Groenescheij
    on Dec 15th, 2009 at 9:36 am

    Thanks for the very clear explanation!

Leave a Comment