I have this strange observation and I don't know how to cope with this:
I'm reading a list of files from a directory. I pipe these through a sequence of Select-Object
, Sort-Object
, Select-Object
calls in order to retrieve just a single property. Finally, I feed the result to a pipe.
Now, when Get-ChildItem
retrieves no files, I get the error message: Cannot bind argument to parameter 'File' because it is null.
function Test
{
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]$File
)
process { }
}
$arr = (Get-ChildItem -Filter '*.xxxx' |
Select-Object -Property 'Name',
@{
name = 'FileObject'
expression = { $_ }
} |
Sort-Object -Property 'Name').FileObject
$arr | Test
(Please note: this is just an MRE, not a meaningful piece of code. Don't focus on the Select-Object
expression.)
When I change the last line to: Sort-Object -Property 'Name')
by removing the .FileObject
, everything runs flawlessly.
An empty array is an empty array, I guess. In both cases, $arr -eq $null
is $true
. So, why do I get different behaviour? How can I make this run flawlessly (and still being strict) with the FileObject
property still being the return type?
There is a difference between $null
and AutomationNull.Value
. When Cmdlets, Functions and Script Blocks return nothing what you actually get is this type of null value but then by expanding on the .FileObject
property when the statement returned Automation.Value
you're effectively getting $null
instead.
If you try to access a property or sub property of an object that doesn't have the specified property, you get a
$null
value like you would for an undefined variable. It doesn't matter if the variable is$null
or an actual object in this case.
See Everything you wanted to know about $null
for more details.
$var1 = $null
$var2 = & { }
function Test {
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]$File
)
begin { 'begin' }
process { 'process' }
end { 'end' }
}
$var1 | Test # fails on `process` block
$var2 | Test # only `begin` and `end` are called, no items are bound from pipeline
$var2.SomProperty | Test # now is `$null`, thus same issue as first example