With:
$data | ConvertFrom-Json | Where-Object { $_.Name -eq 'banana' }
The following happens:
ConvertFrom-Json
returns an array of objects (which is an object itself). As this is the first (in the end also the only) "finished" object ConvertFrom-Json
returns, it is passed as a whole down the pipeline. Remember, a cmdlet could return multiple arrays of objects in general.
So, Where-Object
receives only one object in this case (the whole array with three elements). $_
then references the whole array, not each element. Therefore, $_.Name
does not return the name of one element, but a list of all element names. Furthermore, the term $_.Name -eq 'banana'
in this case is not a boolean expression, but a filtered list of element names (the list then only contains 'banana'). As long as the list is not empty, it will be evaluated to $true
by Where-Object
and therefore your whole array (one object, with three elements) is piped further (printed in your case). So, it doesn't return three objects like you assumed, but one object, containing three objects.
Your other line in contrast:
($data | ConvertFrom-Json) | Where-Object { $_.Name -eq 'banana' }
Well, to make it short, does what you expect it to do. Why? Because the round brackets break the pipeline. Due to the brackets, everything inside the brackets will be completely evaluated, before something gets piped further. After your brackets are evaluated, there is an array, that will be piped further. A whole array will be piped element by element. So in this case, Where-Object
receives three single objects, like you expected it.
Another nice example is this:
You cannot overwrite a file that your are currently reading:
Get-Content test.txt | Set-Content test.txt
But you can overwrite a file after you finished reading it:
(Get-Content test.txt) | Set-Content test.txt