Home > Blockchain >  Cannot validate argument on parameter 'Property' when running Where-object on an array of
Cannot validate argument on parameter 'Property' when running Where-object on an array of

Time:02-17

I guess I'm overlooking something super obvious here... running this code:

$arraytest = @("one", "two", "three")
$arraytest | Where-Object $_ -Like "*hre*" | foreach { Write-Host $_ } 

Produces "Where-Object: Cannot validate argument on parameter 'Property'. The argument is null or empty." in pwsh. I don't understand why. I checked Microsoft docs for pwsh arrays, and also the docs for Where-Object, but no luck. Following this question I replaced the line with:

$arraytest | Where {$_ -match "hre"} | foreach { Write-Host $_ } 

This works. Is there some hidden default parameter I should have referenced in the -Like example? Why does -match work but -like doesn't?

CodePudding user response:

Since PowerShell 3.0, Where-Object has two distinct syntaxes you can use - but you can't mix them the way you're currently trying.

ScriptBlock syntax (or filter script syntax)

This is the "classic" way of using Where-Object, available since PowerShell 2.0 - you supply a scriptblock and Where-Object then uses this block as a predicate for each input item.

It automatically binds the input values to $_ on each iteration so you can do:

... |Where {$_ -match "hre"}
# or 
... |Where {$_ -like "*hre*"}
# or 
... |Where {$_.Length -gt 3}

As you can see, we have full access to the input value itself via $_, as well as any properties the object might have.

Property syntax

After the release of PowerShell 2.0, many community members started sharing reusable scripts and snippets online, and it became clear that:

  • Many people were using the same simple form over and over: {$_.<propertyName> -<operator> <someValue>}
  • The scriptblock syntax was not immediately intuitive (at least not to anyone who didn't have experience with Perl, from which the { $_ } syntax for anonymous sub routines was largely inspired)

For this reason, Where-Object was augmented with a number of parameter sets in version 3.0 that would allow simplification of the most common use case by providing parameters that look like operators:

  • Where {$_.Length -match "hre"} could then be written as Where Length -match hre

The only limitation with the new syntax is that you must supply a target property to compare against - so you can no longer compare against the intrinsic value of whatever input value would have been bound to $_ in a filter script.

For this reason, you have to stick with the classic scriptblock-based syntax:

$arraytest = @("one", "two", "three")
$arraytest |Where-Object { $_ -like "*hre*" } |ForEach-Object { Write-Host $_ } 

In summary:

  • Property syntax is useful for writing concise filtering statements when you want to evaluate a specific property value on the input objects
  • ScriptBlock syntax is required whenever you need to refer to the input object itself via $_

Is there ever a circumstance under which ... | Where-Object $_ -Like "*hre*" is a valid and meaninfful pipeline expression?

Yes!

When you're using Where-Object in a scope where the property name you're filtering on has already been bound to $_:

'Length' |ForEach-Object {
    Get-ChildItem -File |Where-Object $_ -gt 1KB
}
  • Related