Reputation: 30235
Why do the two following snippets produce different output?
Get-Content -Raw "test.json" | ConvertFrom-Json | %{
Write-Output "MessageType: $($_.Messagetype)"
}
# this time make sure Get-Content and ConvertFrom-Json are evaluated completely, before the foreach
(Get-Content -Raw "test.json" | ConvertFrom-Json) | %{
Write-Output "MessageType: $($_.Messagetype)"
}
Executing the snippets with the following json:
[
{
"MessageType": "A"
},
{
"MessageType": "B"
}
]
the first script produces
MessageType: A B
and the second the expected
MessageType: A
MessageType: B
So basically for the first snippet, the foreach gets a single element which is an array with 2 elements, while in the second snippet the foreach is called for every element.
I don't understand why forcing the evaluation completely changes the behavior here.
Upvotes: 2
Views: 118
Reputation: 440132
In PowerShell versions up to v6.x, ConvertFrom-Json
, unlike most other cmdlets, outputs arrays as single objects, instead of sending objects one by one through the pipeline.
Therefore, in your first command's %
(ForEach-Object
) script block, $_
is the entire array, which, inside an expandable string ("..."
) stringifies to a list of its elements separated by spaces by default.
By contrast, enclosing a command in ()
, the grouping operator, turns it into an expression, and using an expression in a pipeline implicitly causes enumeration of the expression's result, causing the objects to be sent one by one.
Note: Another notable side effect of using ()
is that an enclosed command's output is collected in full in memory.
Therefore, your second command's %
(ForEach-Object
) script block is invoked twice, with $_
bound to a single object each.
Simplified examples:
# Sample JSON that is an array comprising 2 objects.
$json = '[
{
"MessageType": "A"
},
{
"MessageType": "B"
}
]'
# PS v6.x-: -> 1, because ConvertFrom-Json sent the array as a whole
$json | ConvertFrom-Json | Measure-Object | % Count
# -> 2, because using (...) resulted in enumeration
($json | ConvertFrom-Json) | Measure-Object | % Count
Upvotes: 2