It's my first time, so let me know if I'm doing something wrong with the layout of my question.
I have a lot of JSON files with filenames that follow a naming convention, i.e. file1.json, file2.json, etc. Each of which are likely to have multiple objects which look like:
[
{
"Forename": "Jim",
"Surname": "Cook",
"Gender": "M",
"DOB": "12-03-1994"
},
{
"Forename": "Sarah",
"Surname": "Parker",
"Gender": "F",
"DOB": "01-02-1983"
},
{
"Forename": "Alan",
"Surname": "Flemming",
"Gender": "M",
"DOB": "27-10-1989"
}
]
In Powershell, I would like to convert these JSON objects into Powershell objects and then select objects with the same value for a property, like people whose first name is "Jim".
So far I've achieved this:
@(Get-ChildItem "file*.json" | %{Get-Content $_.FullName | Out-String | ConvertFrom-Json}) | Where-Object {$_.Forename -eq "Jim"}
This works when there is only one file to work with, which outputs:
Forename Surname Gender DOB
-------- ------- ------ ---
Jim Cook M 12-03-1994
However it fails and outputs all objects when used with multiple files, as though the Where-Object is being ignored. The result can look like this:
Forename Surname Gender DOB
-------- ------- ------ ---
Jim Cook M 12-03-1994
Sarah Parker F 01-02-1983
Alan Flemming M 27-10-1989
Bill Preston M 04-07-1975
Helen Smith F 03-12-2001
Can someone please suggest what I'm doing wrong here and how it can be fixed to get the correct result? Thanks
The problem is that, in Windows PowerShell (the legacy, ships-with-Windows edition of PowerShell whose latest and last version is 5.1), ConvertFrom-Json
outputs (converted-from-)JSON arrays as single objects rather than element by element, as is otherwise typical in PowerShell.
-NoEnumerate
switch was added as an opt-in to the old behavior.This results in the entire array getting output by Where-Object
if (at least) one of its elements has a .ForeName
property with value Jim
, thanks to member-access enumeration.
The workaround is to force enumeration, which in the simplest case is achieved by wrapping the ConvertFrom-Json
call in (...)
:
Get-ChildItem file*.json | ForEach-Object {
(Get-Content -Raw $_.FullName | ConvertFrom-Json)
} | Where-Object { $_.Forename -eq "Jim" }
Note that I've replaced Get-Content $_.FullName | Out-String
with Get-Content -Raw $_.FullName
(PSv3+), which is both more concise and more efficient for retrieving a file's content as a single, multi-line string.