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
TraverseJsonfunction, which took two parameters:$jsonrepresented the JSON object, and$prefiexstored the prefix for nested keys. This function recursively traversed the JSON object and displayed the key-value pairs. - The
TraverseJsonfunction began with theforeachloop, which iterated over the properties of the$jsonobject using$json.PSObject.Properties. - Inside the
foreachloop, the name and value for every property are assigned to the$propertyNameand$propertyValuevariables, respectively. - Then, the above code checked if the
$propertyValuewas a nested object using the-isoperator and the type[System.Management.Automation.PSCustomObject]. If it was, the code entered theifblock. - There was an additional check for the
$prefixvariable within theifblock. 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.Nameand 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.Nameand displayed to the user. - The user was prompted to choose a second-level key. If
exitwas 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.$secondLevelKeyand 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
TraverseJsonfunction called itself recursively with the selected nested value ($json.$firstLevelKey.$secondLevelKey) and an updated prefix ($firstLevelKey + '.' + $secondLevelKey + '.'). - If the
$prefixwas not empty (indicating nested keys), the function recursively calledTraverseJsonon the nested object ($propertyValue) with an updated prefix ($prefix + $propertyName + '.'). - If the
$propertyValuewas an ArrayList, the code entered anelseifblock and iterated over each item in the ArrayList using aforeachloop. It recursively calledTraverseJsonon every item with an updated prefix that included the array index. - If the
$propertyValuewas neither a nested object nor an ArrayList, it entered theelseblock and displayed the full key path along with the corresponding value using theWrite-Hostcmdlet. - Finally, outside the function, the code read the JSON file content using the
Get-Contentcmdlet, converted it to a JSON object usingConvertFrom-Json, and called theTraverseJsonfunction 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.PSVersionto 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.