Table of Contents
Using ConvertFrom-Json
Cmdlet
We can use the ConvertFrom-Json
cmdlet to traverse the JSON file with first and nested-level keys; Let’s explore them below.
Traverse JSON File Containing First-Level Keys
Use ConvertFrom-Json
with the foreach
loop to traverse the JSON file having first-level keys only.
1 2 3 4 5 6 7 |
{ "name": "John Christoper", "age": 40, "city": "Washington" } |
1 2 3 4 5 6 |
$jsonData = Get-Content -Path "./file.json" -Raw | ConvertFrom-Json foreach ($current_property in $jsonData.PSObject.Properties) { Write-Host "$($current_property.Name): $($current_property.Value)" } |
1 2 3 4 5 |
name: John Christoper age: 40 city: Washington |
We used the Get-Content
cmdlet to read the contents of a JSON file located at ./file.json path, which we specified using the -Path
parameter. The -Raw
parameter ensured the file’s entire content was read as a single string before passing to the ConvertFrom-Json
cmdlet.
We used the ConvertFrom-Json cmdlet to convert the JSON string into a PowerShell object (PSObject
), which we stored in the $jsonData
variable. Then, we used the for
loop to iterate over all properties in the $jsonData
.
How did we retrieve all properties? This expression $json.PSObject.Properties
retrieved the properties of the $jsonData
object as a collection.
For each property ($current_property
), we used $current_property.Name
and $current_property.Value
to retrieve the current property name and its corresponding value, respectively.
After that, we constructed a string by combining the property name and its value as "$($current_property.Name): $($current_property.Value)"
to further display on the PowerShell console using the Write-Host
cmdlet.
Let’s take another example, but we will take the key from the user this time; see the following example.
1 2 3 4 5 6 7 |
{ "name": "John Christoper", "age": 40, "city": "Washington" } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$jsonData = Get-Content -Path "./file.json" -Raw | ConvertFrom-Json $key = Read-Host -Prompt "Enter key" foreach ($record in $jsonData) { if ($record | Select-Object -ExpandProperty $key -ErrorAction SilentlyContinue){ Write-Host "$($record.$key)" }else{ Write-Host "The given key was not found." } } |
1 2 3 4 |
Enter key: name John Christopher |
1 2 3 4 |
Enter key: random The given key was not found. |
Again, we used the Get-Content
and ConvertFrom-Json
to read the JSON file’s content and assign it to the $jsonData
variable. After that, we used the Read-Host
cmdlet with the -Prompt
parameter to prompt the user and enter the desired key. We stored this key in the $key
variable.
Next, we used the foreach
loop (a.k.a. foreach
statement) to iterate over the $jsonData
. In each iteration, we piped the $record
to the Select-Object cmdlet with the -ExpandProperty
parameter to select and expand the property given by the $key
.
We set the -ErrorAction
to the SilentlyContinue
to suppress the error message because we wanted to show our custom message rather than the error generated by the PowerShell.
So, if the $key
was present in the JSON file, the Write-Host
cmdlet from the if
block would be executed to print the corresponding value; otherwise, the else
block would be executed to display a message on the console saying the given know not found.
Let’s dive deeper and work with the JSON file with nested keys.
Traverse JSON File Containing First-Level Keys
Use ConvertFrom-Json
with the foreach
loop to traverse the JSON file having nested keys.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
{ "student1": { "name": { "firstName": "John", "lastName": "Doe" }, "age": 30, "Courses": { "CS123": "Introduction to Computer Science", "DS234": "Introduction to DataScience" } }, "student2": { "name": { "firstName": "Thomas", "lastName": "Nelsan" }, "age": 28, "Courses": { "CS123": "Java Programming", "Ph234": "Introduction to Psychology" } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
#Define a function named TraverseJson that takes a JSON object ($json) #and an optional prefix ($prefix) function TraverseJson($json, $prefix = '') { # Iterate over each property in the JSON object foreach ($property in $json.PSObject.Properties) { # Get the name and value of the property $propertyName = $property.Name $propertyValue = $property.Value # Check if the property value is a nested object if ($propertyValue -is [System.Management.Automation.PSCustomObject]) { # Check if it's the first level of keys if ($prefix -eq '') { # Display the available first-level keys Write-Host "First level keys:" foreach ($firstLevelKey in $json.PSObject.Properties.Name) { Write-Host "- $firstLevelKey" } # Prompt the user to choose a first-level key $firstLevelKey = Read-Host "Choose a first level key (enter 'exit' to exit)" # If 'exit' is entered, return and exit the recursion if ($firstLevelKey -eq "exit") { return } # If the chosen first-level key is valid elseif ($json.PSObject.Properties.Name -contains $firstLevelKey) { # Get the available second-level keys for the chosen first-level key $secondLevelKeys = $json.$firstLevelKey.PSObject.Properties.Name Write-Host "Second level keys under '$firstLevelKey':" foreach ($secondLevelKey in $secondLevelKeys) { Write-Host "- $secondLevelKey" } # Prompt the user to choose a second-level key $secondLevelKey = Read-Host "Choose a second level key (enter 'exit' to exit)" # If 'exit' is entered, return and exit the recursion if ($secondLevelKey -eq "exit") { return } # If the chosen second-level key is valid elseif ($secondLevelKeys -contains $secondLevelKey) { # Get the nested value corresponding to the chosen keys $nestedValue = $json.$firstLevelKey.$secondLevelKey Write-Host "Value of '$firstLevelKey.$secondLevelKey': $nestedValue" } else { Write-Host "Invalid second level key. Please try again." } # Recursively call the TraverseJson function with the #nested value and an updated prefix TraverseJson $json.$firstLevelKey.$secondLevelKey ($firstLevelKey + '.' + $secondLevelKey + '.') } else { Write-Host "Invalid first level key. Please try again." } # Return to exit the recursion return } # If it's not the first level of keys else { # Recursively call the TraverseJson function with the #nested object and an updated prefix TraverseJson $propertyValue ($prefix + $propertyName + '.') } } # If the property value is an ArrayList elseif ($propertyValue -is [System.Collections.ArrayList]) { # Iterate over each item in the ArrayList $index = 0 foreach ($item in $propertyValue) { #Recursively call the TraverseJson function with the item #and an updated prefix, including the array index TraverseJson $item ($prefix + $propertyName + "[$index].") $index++ } } # If it's a regular property (not a nested object or ArrayList) else { # Display the key and value Write-Host "${prefix}${propertyName}: ${propertyValue}" } } } #Read the content of the JSON file and convert it to a JSON object $json = Get-Content -Path "./file.json" -Raw | ConvertFrom-Json #Call the TraverseJson function with the JSON object TraverseJson $json |
1 2 3 4 5 6 7 8 9 10 11 12 |
First level keys: - student1 - student2 Choose a first level key from the options above (or enter 'exit' to exit): student1 Second level keys under 'student1': - name - age - Courses Choose a second level key from the options above (or enter 'exit' to exit): age Value of 'student1.age': 30 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
First level keys: - student1 - student2 Choose a first level key from the options above (or enter 'exit' to exit): student2 Second level keys under 'student2': - name - age - Courses Choose a second level key from the options above (or enter 'exit' to exit): Courses Value of 'student2.Courses': @{CS123=Java Programming; Ph234=Introduction to Psychology} student2.Courses.CS123: Java Programming student2.Courses.Ph234: Introduction to Psychology |
Don’t be afraid to look at the code; it is very simple and straightforward; Let’s learn it step by step below:
- First, we defined the
TraverseJson
function, which took two parameters:$json
represented the JSON object, and$prefiex
stored the prefix for nested keys. This function recursively traversed the JSON object and displayed the key-value pairs. - The
TraverseJson
function began with theforeach
loop, which iterated over the properties of the$json
object using$json.PSObject.Properties
. - Inside the
foreach
loop, the name and value for every property are assigned to the$propertyName
and$propertyValue
variables, respectively. - Then, the above code checked if the
$propertyValue
was a nested object using the-is
operator and the type[System.Management.Automation.PSCustomObject]
. If it was, the code entered theif
block. - There was an additional check for the
$prefix
variable within theif
block. We were at the first level of keys if it was an empty string. In this case, the code displayed the available first-level keys by iterating over$json.PSObject.Properties.Name
and prompted the user to choose a first-level key. - If the user entered
exit
, the function returned and exited the recursion. Otherwise, if the chosen first-level key was valid ($json.PSObject.Properties.Name -contains $firstLevelKey
), the code displayed the available second-level keys for the chosen first-level key. - The second-level keys were obtained from
$json.$firstLevelKey.PSObject.Properties.Name
and displayed to the user. - The user was prompted to choose a second-level key. If
exit
was entered, the function returned and exited the recursion. If the chosen second-level key was valid ($secondLevelKeys -contains $secondLevelKey
), the code retrieved the corresponding nested value using$json.$firstLevelKey.$secondLevelKey
and displayed it. - If the chosen second-level key was invalid, an error message was displayed, and the user was prompted to try again.
- Finally, the
TraverseJson
function called itself recursively with the selected nested value ($json.$firstLevelKey.$secondLevelKey
) and an updated prefix ($firstLevelKey + '.' + $secondLevelKey + '.'
). - If the
$prefix
was not empty (indicating nested keys), the function recursively calledTraverseJson
on the nested object ($propertyValue
) with an updated prefix ($prefix + $propertyName + '.'
). - If the
$propertyValue
was an ArrayList, the code entered anelseif
block and iterated over each item in the ArrayList using aforeach
loop. It recursively calledTraverseJson
on every item with an updated prefix that included the array index. - If the
$propertyValue
was neither a nested object nor an ArrayList, it entered theelse
block and displayed the full key path along with the corresponding value using theWrite-Host
cmdlet. - Finally, outside the function, the code read the JSON file content using the
Get-Content
cmdlet, converted it to a JSON object usingConvertFrom-Json
, and called theTraverseJson
function with the JSON object.
So, the above code allowed the user to interactively traverse a JSON object, select keys at different levels, and view their corresponding values. This code is limited to second-level keys; you can add value to it to fit your requirements.
What is the importance of using ConvertFrom-Json
, which compels us to use it in every above solution? Because PowerShell can’t iterate over the JSON objects directly, we used the ConvertFrom-Json
to convert the JSON string to a PSCustomObject, where each property represents a JSON field.
The above solutions will work if you use PowerShell version 3.0+; run the
$PSVersionTable.PSVersion
to check your PowerShell version. If you are using PowerShell version 2.0 or looking for an alternative, the following solution is for you.
Using JavaScriptSerializer
Class
Use the JavaScriptSerializer
class to loop through the JSON if you are using PowerShell version 2.0.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Add-Type -AssemblyName System.Web.Extensions $JS = New-Object System.Web.Script.Serialization.JavaScriptSerializer $json = @' [{"id":1,"firstName":"John","lastName":"Doe","age":32}, {"id":2,"firstName":"Thomas","lastName":"Christoper","age":30},{"id":3,"firstName":"Johny","lastName":"Daniel","age":29}] '@ $data = $JS.DeserializeObject($json) $data.GetEnumerator() | foreach-Object { foreach ($key in $_.Keys){ Write-Host "$key : $($_[$key])" } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
id : 1 firstName : John lastName : Doe age : 32 id : 2 firstName : Thomas lastName : Christoper age : 30 id : 3 firstName : Johny lastName : Daniel age : 29 |
First, we used the Add-Type
command to load the System.Web.Extensions
assembly into the current session. This assembly provides classes for working with JSON data in .NET applications.
Then, we used the New-Object
cmdlet to create an object of the JavaScriptSerializer class from the System.Web.Script.Serialization
namespace, which we stored in the $JS
variable.
After that, we used the DeserializeObject()
method of the $JS
object. This method took JSON string ($json
) as a parameter to deserialize it into the PowerShell object. We stored the resulting object in the $data
variable.
Next, we loop through each item in the $data
using the GetEnumerator()
method and foreach-Object
cmdlet. Inside the foreach-Object
, we used the foreach
loop with the Keys
property of the current item to iterate over each key in the current item. We displayed the corresponding key-value pair using the Write-Host
cmdlet.
That’s all about how to Loop through JSON File in PowerShell.