Friday, August 05, 2011

What do you get when you iterate null?

In most cases, an exception; but in PowerShell you get $null.

Suppose I have folders with 0, 1 and more than 1 file in (called empty, full and two, say) and I want to enumerate the names of the files contained in each, with some general purpose code.

That should be no problem --

and let's write a little reporting function

When we report on the folders in descending order of contained files we get

test (2).txt
test.txt
System.Object[]
2
++test (2).txt++
++test.txt++
-----
test.txt
System.String
8
++test.txt++
-----
Split-Path : Cannot bind argument to parameter 'Path' because it is null.
At C:\Users\Steve\Documents\scratch\Untitled1.ps1:6 char:15
+     Split-Path <<<<  -Leaf $file
    + CategoryInfo          : InvalidData: (:) [Split-Path], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.Split 
   PathCommand
 
You cannot call a method on a null-valued expression.
At C:\Users\Steve\Documents\scratch\Untitled1.ps1:12 char:15
+   $arg.GetType <<<< ().FullName
    + CategoryInfo          : InvalidOperation: (GetType:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
 
++++

Not happy.

The first error is what you get when you work on the foreach over $null, yielding $null; and calling code has to special-case the single item return -- getting the .Length property of the return is not the number of files! For that replace $arg.Length by $arg | Measure-Object | % {write-host $_.Count} .

So try this

where we fight PowerShell's fragmentation of sequences all the way. Now we get what we expected

test (2).txt
test.txt
System.Object[]
2
++test (2).txt++
++test.txt++
-----
test.txt
System.Object[]
1
++test.txt++
-----
System.Object[]
0
-----

Oh, yeah -- the more PowerShell way of doing all this:

No comments :