Here’s a funny thing in Powershell:
PS C:\> cd C:\WINDOWS\system32 PS C:\WINDOWS\system32> (dir *.dll).GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Object[] System.Array PS C:\WINDOWS\system32> (dir kernel32.dll).GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True FileInfo System.IO.FileSystemInfo PS C:\WINDOWS\system32>
See what’s happening? If dir (or actually Get-ChildItem) finds several items matching our criteria then it returns an array, which is what you’d expect. But if the cmdlet finds just a single item then that item is returned directly instead of being encapsulated into an array. If you’re unexperienced with Powershell then that’s probably not what you’re expecting.
For example, this script will not always work as expected:
if ((dir *.dll).Length -gt 1) { 'many items' }
If there is more than 1 matching item then all will be fine, but if exactly one item is found then that script will break. And worse, it will break without the user noticing since no exception is thrown. It will simply print out ‘many items’ in this case, even though there is just one item. To understand why, try this:
PS C:\WINDOWS\system32> (dir kernel32.dll).Length 989696
What happens is that dir returns one item, of type FileInfo, which happens to have a property called Length which contains the size of the file. Thus we’re calling System.IO.FileInfo.Length instead of System.Array.Length… Very confusing!
Fortunately, there’s an easy way to make sure that you always get an array, namely the @(…) construct which does nothing if its expression evaluates to an array and if it doesn’t, encapsulates it into one.
Examples:
PS C:\WINDOWS\system32> @(dir kernel32.dll).Length 1 PS C:\WINDOWS\system32> if (@(dir *.dll).Length -gt 1) { 'many items' }
To sum it up: Always use @(…) if you want to work with arrays! Note that this applies to all cmdlets, not just Get-Childitem!
/Emil