Check if jObject exists in json File - Powershell - json

how can I check if the Object 'Production' in my json-File exists in Powershell?
an extract of my json File:
[
{
"UID": "x,
"Office": "xy",
"Production": "a"
}
]
In this case the key "Production" does exist in the json File. But that is not always the case.
How can I check if it exists via Powershell? With Get-Member?
my approach:
$json = Get-Content "C:\file.json" | ConvertFrom-Json
foreach ($item in $json) {
if (Get-Member -InputObject $item.Production) {Write-Host "Production exists"}
else {Write-Host "Production does not exist"}
}
THANKS!

You could check if the property exists by accessing the object's PSObject.Properties, one of the many ways to validate could be using the .Item(..) method:
$json = '[{ "Production": "Hello" }, { "OtherProp": "Nothing Here" }]' | ConvertFrom-Json
$count = 0
foreach($item in $json) {
$index = 'Object {0}' -f $count++
if($prop = $item.PSObject.Properties.Item('Production')) {
"{0}: Production Exists and it's value is: '{1}'" -f $index, $prop.Value
}
else {
"{0}: No property with name Production" -f $index
}
}
You can also use the property name to index to the NoteProperty Object with the following syntax:
if($prop = $item.PSObject.Properties['Production']) {
The first object from the example Json has a property with Name Production and Hello as Value while the second object does have the specified property. Above would result in:
Object 0: Production Exists and it's value is: 'Hello'
Object 1: No property with name Production

Related

How to convert json string into specified hashtable format with 5.1 powershell version?

I'm trying to convert json string into desired format of hashtable with powershell 5.1 version.
Used this code to convert json into hashtable but getting the o/p in the below mentioned format. How to convert this json into specified format of hashtable ?
My code :
function ConvertTo-Hashtable {
[CmdletBinding()]
[OutputType('hashtable')]
param (
[Parameter(ValueFromPipeline)]
$InputObject
)
process {
## Return null if the input is null. This can happen when calling the function
## recursively and a property is null
if ($null -eq $InputObject) {
return $null
}
## Check if the input is an array or collection. If so, we also need to convert
## those types into hash tables as well. This function will convert all child
## objects into hash tables (if applicable)
if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) {
$collection = #(
foreach ($object in $InputObject) {
ConvertTo-Hashtable -InputObject $object
}
)
## Return the array but don't enumerate it because the object may be pretty complex
Write-Output -NoEnumerate $collection
} elseif ($InputObject -is [psobject]) { ## If the object has properties that need enumeration
## Convert it to its own hash table and return it
$hash = #{}
foreach ($property in $InputObject.PSObject.Properties) {
$hash[$property.Name] = ConvertTo-Hashtable -InputObject $property.Value
}
$hash
} else {
## If the object isn't an array, collection, or other object, it's already a hash table
## So just return it.
$InputObject
}
}
}
json :
$json = '[
{
"type": "IP",
"Fields": [
{
"Column": "FileHash",
"Id": "Address"
}
]
}
]'
Actual Format with my code:
Name Value
---- -----
Fields {System.Collections.Hashtable}
type IP
Desired Format :
Key : type
Value : IP
Name : type
Key : Fields
Value : {FileHash}
Name : Fields

powershell - iterate over json keys that have similar name

I have a json block containing keys that have a similar name, each is numbered. I want to iterate over those keys. How can this be achieved?
Eg
$json = #"
{
"output": [
{
"AIeventCheck1": "A",
"AIeventCheck2": "B",
"AIeventCheck3": "C"
}
]
}
"#
$config = $json | ConvertFrom-Json
ForEach ($AIeventCheck in $config.output) {
Write-host AIeventCheck value: $AIeventCheck
}
target output:
A
B
C
Use the psobject memberset to access the individual properties of the object(s):
foreach($AIeventCheck in $config.output){
$AIEventCheckValues = $AIEventCheck.psobject.Properties |Where Name -like 'AIeventCheck*' |ForEach-Object Value
Write-Host AIeventCheck value: $AIeventCheckValues
}

How to add additional elements in an existing json file

This is what I am doing:
$appParametersXml = [Xml] (Get-Content "$appParameterFilePath\$appParameterFile")
$parameterJsonFile = "$appParameterFilePath\$applicationName"+ "." + $jsonFileName
# Transform the "Parameter" elements into a nested hashtable.
# Convert any values that can be interpreted as [int] to [int] and strip out any comments in the xml file.
$hash = [ordered] #{}
$appParametersXml.Application.Parameters.ChildNodes | Where-Object {$_.NodeType -ne 'Comment'} | % {
$hash[$_.Name] = #{ value = if ($num = $_.Value -as [int]) { $num } else { $_.Value }
}
}
# Wrap the hashtable in a top-level hashtable and convert to JSON.
[ordered] #{
'$schema' = 'https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#'
contentVersion ='1.0.0.0'
parameters = $hash
} | ConvertTo-Json |Out-File $parameterJsonFile
Write-Host "The JSON File is: " $parameterJsonFile
After I build the hash table with existing information from the XML file, I need to add additional parameter values like this Before converting to JSON
"parameters": {
"applicationName": {
"value": "somevalue"
},
"applicationTypeName": {
"value": "somevalue"
},
"applicationTypeVersion": {
"value": "somevalue"
},
Everything that I have tried so far has given me this as additional values. The regular XML values are being converted the correct way but the additional items that I am adding before converting are coming up like this!
"applicationName": "somevalue"
How can i seperate that out on different lines?
So, assuming your input xml file looks something like this ...
<application>
<parameters>
<applicationName>My Awesome App</applicationName>
<!--my awesome comment-->
<applicationTypeName>Mobile App</applicationTypeName>
<applicationTypeVersion>299</applicationTypeVersion>
<!--my other awesome comment-->
</parameters>
</application>
Here is my revised PowerShell ... you can't use if ($num = $_.Value -as [int]) casting as it won't work for 0, as it would be interpreted as false. I prefer to break the steps down and test and check each. Also I've used InnerText for the node value instead of Value as typically Value is evaluated as $null and I'm not sure what your xml looks like.
$fileXml = "./config.xml"
$fileJson = "./config.json"
$xmlContent = [Xml](Get-Content $fileXml)
# Transform the "Parameter" elements into a nested hashtable.
# Set any string values which are integers as [int] and strip out any comments in the xml file.
$parameters = [ordered]#{}
$nodes = $xmlContent.application.parameters.ChildNodes.Where{ $_.NodeType -ne 'Comment' }
foreach ($node in $nodes) {
$parameter = $node.Name
$value = $node.InnerText
if ($value -match "^\d+$") { $value = [int] $value }
$parameters.Add($parameter, #{ value = $value })
}
# if you need to add additional attributes, it's as simple as:
$parameters.Add("newParameter1", #{ value = "newValue1" })
$parameters.Add("newParameter2", #{ value = "newValue2" })
# Wrap the hashtable in a top-level hashtable and convert to JSON.
[ordered]#{
'$schema' = 'https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#'
contentVersion = '1.0.0.0'
parameters = $parameters
} | ConvertTo-Json | Out-File $fileJson
And here is the output saved to the json file:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"applicationName": {
"value": "My Awesome App"
},
"applicationTypeName": {
"value": "Mobile App"
},
"applicationTypeVersion": {
"value": 299
},
"newParameter1": {
"value": "newValue1"
},
"newParameter2": {
"value": "newValue2"
}
}
}
In case anyone else runs into this, it was as simple as doing this after the hash table gets created with the existing XML file
$appParametersFileName = "$appParameterFilePath\$appParameterFile"
$appParametersXml = [Xml] (Get-Content "$appParametersFileName")
$parameterJsonFile = "$appParameterFilePath\$applicationName"+ "." + $jsonFileName
# Transform the "Parameter" elements into a nested hashtable.
# Convert any values that can be interpreted as [int] to [int] and strip out any comments in the xml file.
$hash = [ordered] #{}
$appParametersXml.Application.Parameters.ChildNodes | Where-Object {$_.NodeType -ne 'Comment'} | % {
$hash[$_.Name] = #{ value = if ($num = $_.Value -as [int]) { $num } else { $_.Value }
}
}
$hash["newvalue1"]=#{ value="value1"}
$hash["newvalue2"]=#{ value="value2"}
# Wrap the hashtable in a top-level hashtable and convert to JSON.
[ordered] #{
'$schema' = 'https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#'
contentVersion ='1.0.0.0'
parameters = $hash
} | ConvertTo-Json |Out-File $parameterJsonFile
Write-Host "The JSON File is: " $parameterJsonFile

Reading a json file in key value pair in the same order that's given in input

I am writing a PowerShell Script, which will read a json file having different sections, like job1, job2 and so on.. Now my objective is to read each section separately and to loop through it as a key value pair. I also need to maintain the order of the input file, because the jobs are scheduled in sequence. and these jobs run taking the values from the json file as input.
I tried using Powershell version 5.1, in which I created PSCustomObject but the order is getting sorted alphabetically, which I DON'T want.
Json File :
{ "Job1": [
{
"Ram" : "India",
"Anthony" : "London",
"Elena" : "Zurich"
}],
"Job2": [
{
"Build" : "fail",
"Anthony" : "right",
"Sam" : "left"
}]}
$json = Get-Content -Path C:\PowershellScripts\config_File.json |
ConvertFrom-Json
$obj = $json.Job1
$json.Job1 | Get-Member -MemberType NoteProperty | ForEach-Object {
$key = $_.Name
$values = [PSCustomObject][ordered]#{Key = $key; Value = $obj."$key"}
$values
}
I am expecting to loop through each section separately and in the same order that's provided in the json file. For example looping through Job1 section and to fetch only the Values in the same order that's in the json file.
I will guarantee that this is not the best way to do this, but it works.
$json = Get-Content -Path C:\PowershellScripts\config_File.json |
ConvertFrom-Json
$out = ($json.Job1 | Format-List | Out-String).Trim() -replace "\s+(?=:)|(?<=:)\s+"
$out -split "\r?\n" | ForEach-Object {
[PSCustomObject]#{Key = $_.Split(":")[0]; Value = $_.Split(":")[1]}
}
Explanation:
The JSON object is first output using Format-List to produce the Property : Value format, which is piped to Out-String to make that output a single string. Trim() is used to remove surrounding white space.
The -replace removes all white space before and after : characters.
The -split \r?\n splits the single string into an array of lines. Each of those lines is then split by the : character (.Split(":")). The [0] index selects the string on the left side of the :. The [1] selects the string on the right side of the :.
Can you change the json schema?
I would probably make changes to the json schema before i tried to parse this (if possible of course).
Like this (changed only Job1):
$json = #"
{ "Job1": [
{
"Name": "Ram",
"Location" : "India"
},
{
"Name": "Anthony",
"Location": "London"
},
{
"Name": "Elena" ,
"Location": "Zurich"
}
],
"Job2": [
{
"Build" : "fail",
"Anthony" : "right",
"Sam" : "left"
}]}
"# | convertfrom-json
foreach ($obj in $json.Job1) {
$key = $obj.Name
$values = [PSCustomObject][ordered]#{Key = $key; Value = $obj."$key" }
$values
}

How to replace a property in a json file in powershell

I'm having a difficult time reading in a JSON file in powershell, replacing a value and writing back to the file or a file.
Given the following:
[Object]$QuickJson = #'
{
"swagger": "1.0",
"info": {
"version": "0.0.1",
"title": "this is a title",
"description": "this is a description"
},
"basePath": "/test",
"paths" : {
"/GetSomething": {
"get": {
"name" : "test01"
}
},
"/GetSomethingElse" : {
"get": {
"name" : "test02"
}
},
"/GetAnotherThing": {
"get": {
"name" : "test03"
}
}
}
}
'#
What I'm interested in here is replacing the values in the "paths" object with something else. I read the file and can access the object however with what I'm trying:
[object]$MyPSJson = ConvertFrom-Json -InputObject $QuickJson
foreach($info in $MyPSJson.paths.PSObject.Properties)
{
$path = $info.Name
Write-Host "path: $path"
$info.Name = "$path?code=fsfsfsfsfsfdfds"
Write-Host $info.Name
}
I don't know what those "paths" will be, I need to take the existing value and append a code value to it so I need to be able to iterate through all the paths and do this replacement. When I try the above I get an error:
path: /GetSomething
-- 'Name' is a ReadOnly property. At C:\scripts\test.ps1:44 char:5
+ $info.Name = "$path?code=fsfsfsfsfsfdfds"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
I've tried several different things and yet to come up with a good, or workable for that matter, solution. Any help or pointing in the right direction is greatly appreciated.
You could do something very similar to what you have now, just instead of changing the existing properties you record the initial properties, add new ones with the modifications you want, then set $MyPSJson.paths to itself excluding the old properties, so all it has are the new properties.
#Find initial paths
$Paths=$MyPSJson.paths.psobject.Properties.Name
#Add new paths with the modification to the name, and set the value to the same as the old path
$Paths|%{Add-Member -InputObject $MyPSJson.paths -NotePropertyName "$_`?code=fsfsfsfsfsfdfds" -NotePropertyValue $MyPSJson.paths.$_}
#Set the paths object to itself, excluding the original paths
$MyPSJson.paths = $MyPSJson.paths|Select * -ExcludeProperty $Paths
Try the following (PSv3+):
$MyPSJson.paths = $MyPSJson.paths.psobject.properties |
ForEach-Object { $renamedProps = [ordered] #{} } {
$renamedProps[$_.Name + '?foo=bar&baz=bam'] = $_.Value
} { [pscustomobject] $renamedProps }
Of technically necessity, this recreates the .paths object with modified property names.
It does so by enumerating the original properties, adding their values under the modified name to an ordered hashtable, which on completion of the pipeline is converted to a custom object ([pscustomobject]).
As for what you tried:
A given object's properties cannot be renamed - only its properties' values can be changed.
Therefore, you must create a new object with the desired new property names and the same values as the original.
As an aside: an [object] cast is pointless in PowerShell - it is an effective no-op.
By contrast, a [pscustomobject] cast can be used to create [pscustomobject] instances from [ordered] hashtables, which is the technique used above; casting from other types is again a virtual no-op.
In addition to the accepted answer which worked for me I also found another way which was initially suggested which was to use a hashtable:
function Convert-JsonFileToHashTable([string]$file) {
$text = [IO.File]::ReadAllText($file)
$parser = New-Object Web.Script.Serialization.JavaScriptSerializer
$parser.MaxJsonLength = $text.length
$hashtable = $parser.Deserialize($text, #{}.GetType())
return $hashtable
}
$hashtable = Convert-JsonFileToHashTable (Resolve-Path -Path $DefinitionFile)
$keys = New-Object System.Collections.ArrayList($null)
$keys.AddRange($hashtable["paths"].Keys)
foreach ($key in $keys)
{
$newPath = $key + "?code=$Code"
$hashtable["paths"].$newPath = $hashtable["paths"].$key
$hashtable["paths"].Remove($key) | Out-Null
}
$json = $hashtable | ConvertTo-Json -Depth 20
Write-Output $json | Out-File $newFile -Encoding utf8