1

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

0

1 Answer 1

4

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.

  • Note: In PowerShell (Core) 7, the behavior was changed to align with the usual enumeration-of-elements behavior, and a -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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.