can someone please tell me what I am doing wrong here? I am trying to add additional properties to an existing JSON file.
This is my existing JSON File:
{
"filePath": "F:\\Program Files (x86)\\Common Files\\XXXX\\Services\\file.exe",
"Services": {
"BBBBBB": {
"Id": "BBBBBB",
"Installed": true,
"OverrideValues": {}
},
"XXXX1Service": {
"Id": "XXXX1Service",
"Installed": true,
"OverrideValues": {
"HostName": {
"Enabled": true,
"Value": "my.com"
}
}
},
"XXXX2Service": {
"Id": "XXXX2Service",
"Installed": true,
"OverrideValues": {
"Application Tier URL": {
"Value": "my.com"
},
"HostName": {
"Enabled": true,
"Value": "my.com"
}
}
},
"XXXX3Service": {
"Id": "XXXX3Service",
"Installed": true,
"OverrideValues": {
"HostName": {
"Enabled": true,
"Value": "my.com"
}
}
},
"XXXX4Service": {
"Id": "XXXX4Service",
"Installed": true,
"OverrideValues": {
"HostName": {
"Enabled": true,
"Value": "my.com"
}
}
}
}
}
I am trying to insert properties to make it look like this (look under XXX3Service):
{
"filePath": "F:\\Program Files (x86)\\Common Files\\XXXX\\Services\\file.exe",
"Services": {
"BBBBBB": {
"Id": "BBBBBB",
"Installed": true,
"OverrideValues": {}
},
"XXXX1Service": {
"Id": "XXXX1Service",
"Installed": true,
"OverrideValues": {
"HostName": {
"Enabled": true,
"Value": "my.com"
}
}
},
"XXXX2Service": {
"Id": "XXXX2Service",
"Installed": true,
"OverrideValues": {
"Application Tier URL": {
"Value": "my.com"
},
"HostName": {
"Enabled": true,
"Value": "my.com"
}
}
},
"XXXX3Service": {
"Id": "XXXX3Service",
"Installed": true,
"OverrideValues": {
"HostName": {
"Enabled": true,
"Value": "my.com"
},
"XXX 3 Service": {
"Enabled": true
},
"My Token": {
"Value": "1234567890"
},
"Authority": {
"Value": "authority.com"
},
"ThisSecret": {
"Value": "1234-1234-1234-1234"
}
}
},
"XXXX4Service": {
"Id": "XXXX4Service",
"Installed": true,
"OverrideValues": {
"HostName": {
"Enabled": true,
"Value": "my.com"
}
}
}
}
}
My Code looks like this:
# Get json content from a file
$json = Get-Content .\source.json
# convert the json to be a powershell object
$psObject = $json | ConvertFrom-Json
# useful for referencing to see all of the properties
# $psObject.Services | Select-Object *
# $psObject.Services.XXXX3Service
# $psObject.Services.XXXX3Service.OverrideValues
#* ConvertTo-Json the max allowed depth is 100
$newProperty = #"
{
"OverrideValues": {
"HostName": {
"Enabled": true,
"Value": "my.com"
},
"XXX 3 Service": {
"Enabled": true
},
"My Token": {
"Value": "1234567890"
},
"Authority": {
"Value": "authority.com"
},
"ThisSecret": {
"Value": "1234-1234-1234-1234"
}
}
}
"# | ConvertFrom-Json -Depth 100
# get the name to overwrite the existing property so it's not nested
$propName = $newProperty.PSObject.Properties | Select-Object -Expand Name
# here we supply the $propname value in json as well as use the value(s) under the $newProperty to overwrite the existing property
$psObject.Services.XXXX3Service | Add-Member -MemberType NoteProperty -Name $propName -Value $newProperty.$propName -Force
# lastly convert and export the json
$psObject | ConvertTo-Json -Depth 100 | Out-File "C:\temp\good.json"
however I am getting the following errors:
ConvertFrom-Json : A parameter cannot be found that matches parameter name 'Depth'.
At C:\Users\user\Downloads\json.ps1:38 char:23
+ "# | ConvertFrom-Json -Depth 100
+ ~~~~~~
+ CategoryInfo : InvalidArgument: (:) [ConvertFrom-Json], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.ConvertFromJsonCommand
Add-Member : Cannot bind argument to parameter 'Name' because it is null.
At C:\Users\user\Downloads\json.ps1:44 char:77
+ ... Service | Add-Member -MemberType NoteProperty -Name $propName -Value ...
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Add-Member], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.AddMemberCo
mmand
tl;dr
Remove -Depth 100 from your ConvertFrom-Json call.
With ConvertFrom-Json, use of -Depth is generally not needed, and in Windows PowerShell that parameter doesn't even exist (whereas it does for the complementary cmdlet, ConvertTo-Json, where it is often needed).
As Cpt.Whale points out, in Windows PowerShell the ConvertFrom-Json - note the From - does not have a -Depth parameter. It exists in PowerShell (Core) 7+, where, however, it is rarely needed.
Despite the parameter having the same name as ConvertTo-Json's (see below), it functions very differently: It is used to enforce that the input JSON isn't more deeply nested than the given -Depth value, and reports an error if it is.
As zett42 points out, the default value is 1024, so only more deeply nested JSON would cause an error - which seems unlikely. However, you can use -Depth to increase that limit, up to 2,147,483,647 ([int]::MaxValue), at least formally.
By contrast, ConvertTo-Json - note the To - does have this parameter in Windows PowerShell too, and, unfortunately, it is frequently needed:
By default, PowerShell limits the serialization depth to two levels of recursion, necessitating an explicit -Depth argument to properly serialize more deeply nested object graphs - see this post. Absent that, if the default serialization depth is exceeded, quiet truncation occurs in Windows PowerShell, whereas in PowerShell (Core) you now at least get a warning.
Related
I have a big target json file (parameters_general.json) where all common settings for a deployment are set.
For each tier I have another json file (ex: parameters_dev.json, parameters_test.json, ....) Settings set in one needs tobe added to the general.json, or overwrite it when already in general.
ex: parameters_general.json
{
"general": {
"db_Policy": {
"type": "Periodic",
"databaseAccountOfferType": "Standard",
"periodicModeProperties": {
"backupIntervalInMinutes": 240,
"backupRetentionIntervalInHours": 8,
"backupStorageRedundancy": "Local"
}
},
"databases": [
{
"name": "CtrlWps",
"Containers": [
{
"name": "ControllerAuthentication",
"partitionKey": "id"
}
],
"ContainersTTL": []
},
{
"name": "CpoOcpi",
"Containers": [
{
"name": "Cpos",
"partitionKey": "cpoId"
},
{
"name": "OcpiCdrLastRecoveries",
"partitionKey": "id"
},
{
"name": "Routes",
"partitionKey": "ocpiCpoId"
}
],
"ContainersTTL": [
{
"name": "OcpiCdrs",
"partitionKey": "pk",
"ttl": 172800
},
{
"name": "OcppTransactionIds",
"partitionKey": "pk",
"ttl": 172800
},
{
"name": "Sessions",
"partitionKey": "pk",
"ttl": 172800
}
]
}
],
"system_engineers": [
],
}
}
If I want to updatethis with.
ex: parameters_test.json
{
"general": {
"system_engineers": [
{
"name": "hans",
"AppPrincipalId": "<id>",
"permissions": [
"get",
"list"
]
},
{
"name": "John do",
"AppPrincipalId": "<pid>",
"permissions": [
"all"
]
}
]
}
}
This works, the users are added to the empty "sytem_engineers" node in the parameters_general.json.
However, If I just want to change a setting on a lower node example:
ex: parameters_dev.json
{
"general": {
"databases": [
{
"name": "CtrlWps",
"Containers": [
{
"name": "ControllerAuthentication",
"partitionKey": "pk"
}
]
}
]
}
}
for replacing the partitionKey in one of the databases it replaces the whole "databases" part so I lose all other database configurations in the target.
The code I use is the following.
function ExtendJSON($base, $ext)
{
$propNames = $($ext | Get-Member -MemberType *Property).Name
foreach ($propName in $propNames) {
if ($base.PSObject.Properties.Match($propName).Count) {
if ($base.$propName.GetType().Name -eq "PSCustomObject")
{
$base.$propName = ExtendJSON $base.$propName $ext.$propName
}
else
{
$base.$propName = $ext.$propName
}
}
else
{
$base | Add-Member -MemberType NoteProperty -Name $propName -Value $ext.$propName
}
}
return $base
}
$tier = 'dev'
$parametersJsonGeneral = Get-Content -Path "./parameters/parameters_general.json" | ConvertFrom-Json
#Write-Output "#####################"
$parametersJsonTier = Get-Content -Path "./parameters/parameters_$($tier).json" | ConvertFrom-Json # overwrites existing values in $parametersJsonGeneral
ExtendJSON $parametersJsonGeneral $parametersJsonTier
Is there a way to loop over the settings from the lowest level up to the higher, and replace only these?
The proposed answer does only work one 1st level THIS WORKS
function merger ($target, $source) {
$source.psobject.Properties | ForEach-Object {
if ($_.TypeNameOfValue -eq 'System.Management.Automation.PSCustomObject' -and $target."$($_.Name)" ) {
merger $target."$($_.Name)" $_.Value
}
else {
$target | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $_.Value -Force
}
}
}
$Json1 ='{
"a": {
"b":"asda"
},
"c": "asdasd"
}
' | ConvertFrom-Json
$Json2 = '{
"a": {
"b":"d"
}
}
' | ConvertFrom-Json
merger $Json1 $Json2
However with this I loose data in $Json1
$Json1 ='{
"a": {
"b": [
{
"name": "admin",
"appconfig": {
"test1": true,
"test2": false
}
}
]
},
"c": "asdasd"
}
' | ConvertFrom-Json
$Json2 = '{
"a": {
"b": [
{
"name": "admin",
"appconfig": {
"test1": false
}
}
]
}
}
' | ConvertFrom-Json
merger $Json1 $Json2
{
"a": {
"b": [
{
"name": "admin",
"appconfig": {
"test1": false
}
}
]
},
"c": "asdasd"
}
test2 is gone!
I don't have enough rep to post general comments yet, so I'll have to post it as an answer:
I tested the code in this answer to another question, and it did what you asked. The advantage of this answer is that it doesn't depend on importing a separate module.
There's another answer in the same question that provides link to a more general module that provides for different types of merges (Left Join, Inner Join, etc.) here, which links to here. However, one commenter said that it didn't work with powershell 7.0.
I need help with looping through the following JSON file and pull in all the attributes under "snapshot_groupSnapshotChildren""entitySnapshot_properties" For example the "Test", "Guacamole" and the "Heartbeat on Guacamole" are dynamic and the depth can also vary from one subgroup to another subgroup.
JSON File
{
"snapshot_groupSnapshotChildren": {
"Test": {
"entitySnapshot_properties": {
"_dependsCondition": "good",
"_nextID": "2",
"_name": "Test",
"_externalId": "baa97724-9ff8-46ad-b23a-d37d283905d7",
"objcategory": "",
"_id": "1951498570",
"_class": "SubGroup",
"_group": "1951498570",
"_enabled": "true",
"_ownerID": "__SiteScopeRoot__"
},
"snapshot_groupSnapshotChildren": {
"Guacamole": {
"entitySnapshot_properties": {
"_dependsCondition": "good",
"_nextID": "2",
"_name": "Guacamole",
"_externalId": "f08b1069-1943-479d-bb83-7668d833fa58",
"objcategory": "",
"_id": "1951498571",
"_class": "SubGroup",
"_group": "1951498571",
"_enabled": "true",
"_ownerID": "1951498570"
},
"snapshot_groupSnapshotChildren": {},
"entitySnapshot_name": "Guacamole",
"snapshot_alertSnapshotChildren": {},
"entitySnapshot_url": "",
"snapshot_monitorSnapshotChildren": {
"Heartbeat on Guacamole": {
"entitySnapshot_properties": {
"_prioritySelection": "MEASURMENT",
"_prevKeyAttrMap": "-84.-19.0.5.115.114.0.19.106.97.118.97.46.117.116.105.108.46.65.114.114.97.121.76.105.115.116.120.-127.-46.29.-103.-57.97.-99.3.0.1.73.0.4.115.105.122.101.120.112.0.0.0.0.119.4.0.0.0.0.120.",
"_name": "Heartbeat on Guacamole",
"_frequency": "600",
"_externalId": "80c24825-c540-4e9d-8203-df83333e0a55",
"_reportTopology": "true",
"_eventPreferenceId": "CommonEventInstancePreferences_default",
"_ownerID": "1951498571"
},
"monitor_snapshot_hostName": "<hostname>",
"monitor_snapshot_fullyQualifiedTarget": "<hostFQDN>",
"entitySnapshot_name": "Heartbeat on Guacamole",
"snapshot_alertSnapshotChildren": {},
"entitySnapshot_url": ""
}
}
}
},
"entitySnapshot_name": "Test",
"snapshot_alertSnapshotChildren": {},
"entitySnapshot_url": "",
"snapshot_monitorSnapshotChildren": {}
}
},
"entitySnapshot_name": "SiteScopeRoot",
"snapshot_alertSnapshotChildren": {},
"snapshot_preferenceSnapShot": {},
"entitySnapshot_url": "",
"snapshot_monitorSnapshotChildren": {}
}
Here is my draft code for looping through, which returns an error that "snapshot_groupSnapshotChildren" dosent exist.
$info = Get-Content -Path .\input.json
If($info -eq $null){
Write-Host "Unhandled Exception parsing data for $sitescopeFQDNhost`nExit Script" -ForegroundColor Red -BackgroundColor Black
Exit
}
else{
$ResJsonObj = $info | ConvertFrom-Json #-Depth 99
foreach ($t in $ResJsonObj.PSObject.Properties)
{
Write-Host $t.name
Write-Host $t.value
}
}
Let me know how i can loop through the nested json file to strip out the atributes values under each "entitySnapshot_properties", I a intrested to fetch the following attribute values
Test -->_name, _class
2.Guacamole -->_name,_ownerid
Heartbeat on Guacamole --> _name,monitor_snapshot_hostName
I want to get lines which are serviceArea equal Skype like below.
{
"id": 127,
"serviceArea": "Skype",
"serviceAreaDisplayName": "Skype for Business Online and Microsoft Teams",
"urls": [
"*.skype.com"
],
"tcpPorts": "80,443",
"expressRoute": false,
"category": "Default",
"required": true
},
{
"id": 128,
"serviceArea": "Common",
"serviceAreaDisplayName": "Microsoft 365 Common and Office Online",
"urls": [
"*.config.office.net",
"*.manage.microsoft.com"
],
"tcpPorts": "443",
"expressRoute": false,
"category": "Default",
"required": true
},
{
"id": 130,
"serviceArea": "Common",
"serviceAreaDisplayName": "Microsoft 365 Common and Office Online",
"urls": [
"lpcres.delve.office.com"
],
"tcpPorts": "443",
"expressRoute": false,
"category": "Default",
"required": true
},
{
"id": 146,
"serviceArea": "Skype",
"serviceAreaDisplayName": "Skype for Business Online and Microsoft Teams",
"urls": [
"statics.teams.microsoft.com"
],
"tcpPorts": "443",
"expressRoute": false,
"category": "Default",
"required": true
}
My desired output :
*.skype.com
statics.teams.microsoft.com
Assuming your JSON is wrapped in an array (as mentioned in comments above), you could do something like this to filter the data.
param(
$jsonFile = "$PSScriptRoot\data.json",
$likeFilter = "*Skype*"
)
$convertedObjects = Get-Content -Path $jsonFile | ConvertFrom-Json
$result = $convertedObjects | Where-Object { $_.serviceArea -like $likeFilter }
$result
Your JSON is invalid due to is has no root element. As I see, it is array (list)
$text = #'
[
<your text here>
]
'#
After that, you can select urls
$result = $text |
ConvertFrom-Json |
Where-Object { $_.serviceArea -eq 'Skype' } |
ForEach-Object { return $_.urls }
I'm trying to build a json document which takes it's structure, column names and some values from an already existing base json document, and sets other values to variables assigned via powershell 5.1 in a foreach-object loop.
I tried editing a copy of the base json and creating a new one entirely and I can get close to what I want but not exactly.
A cut down example json document is:
[
{
"name": "Application1",
"tags": ["monitor"],
"description": "Get information about application 1.",
"query":
[
{
"target": {
"version": ["v1","v2","v3","v4","v5"],
"platform": ["Windows","Linux"]
},
"implementation": {
"action": "do something"
}
}
]
},
{
"name": "Application2",
"tags": ["monitor"],
"description": "Get information about application 2",
"query":
[
{
"target": {
"version": ["v1","v2","v3"],
"platform": ["Windows"]
},
"implementation": {
"action": "do something for v1, v2 and v3"
}
},
{
"target": {
"version": ["v4","v5"],
"platform": ["Windows"]
},
"implementation": {
"action": "do something for v4 and v5"
}
}
]
}
]
My script currently looks like:
$BaseJson = (Get-Content "$SourcePath\probes.json" | ConvertFrom-Json)
$ClientConfig = #"
{
"targetHost": "$DigitalSymphonyHost",
"targetPort": "$DigitalSymphonyPort",
"source": "$TargetSqlInstance",
"sensor": {}
}
"#
$ClientJson = ConvertFrom-Json -InputObject $ClientConfig
$BaseJson | Where-Object {$_.tags -contains "monitor"} | ForEach-Object {
# For each sensor in the base-sensors json document
$SensorName = $_.name
$Severity = 2
$Version = $_.query.target.version
$Platform = $_.query.target.platform
$Query = $_.query.implementation.action
$Sensor =#"
{
"severity": "$Severity",
"sensorId": "$SensorId",
"type": "$Type",
"target": {
"version": "$Version",
"platform": "$Platform",
"engineEdition": "$Edition"
},
"implementation": {
"query": "$Query"
}
}
"#
$ClientJson.sensor | Add-Member -Name $SensorName -Value (ConvertFrom-Json $Sensor) -MemberType NoteProperty
}
$ClientJson | ConvertTo-Json | Out-File "$DestinationPath\client-sensors.json"
My desired result is to add the $SensorId as per:
[
{
"targetHost": "servername",
"targetPort": "port",
"source": "servername",
"sensor": [{
"name": "Application1",
"sensorId": "<value_from_$SensorId>",
"tags": [],
"description": "Get information about application 1.",
"query":
[
{
"target": {
"version": ["v1","v2","v3","v4","v5"],
"platform": ["Windows","Linux"]
},
"implementation": {
"action": "do something"
}
}
]
},
{
"name": "Application2",
"sensorId": "<value_from_$SensorId>",
"tags": [],
"description": "Get information about application 2",
"query":
[
{
"target": {
"version": ["v1","v2","v3"],
"platform": ["Windows"]
},
"implementation": {
"action": "do something for v1, v2 and v3"
}
},
{
"target": {
"version": ["v4","v5"],
"platform": ["Windows"]
},
"implementation": {
"action": "do something for v4 and v5"
}
}
]
}]
}
]
My current result is
{
"targetHost": "servername",
"targetPort": "port",
"source": "server",
"sensor": {
"applicationname1": {
"tags": ["monitor],
"description": "Get information about application 2",
"sensorId": "420",
"target": "#{version=v1,v2,v3,v4,v5; platform=Windows Windows;}",
"action": "do something for v4 and v5"
}
}
}
I'm not sure where you're getting sensorID, but I'd do this more like the below:
param(
$SourcePath = $PSScriptRoot,
$DestinationPath = $PSScriptRoot,
$DigitalSymphonyHost = 'SomeHost',
$DigitalSymphonyPort = '8765',
$TargetSqlInstance
)
$BaseObj = (Get-Content "$SourcePath\probes.json" | ConvertFrom-Json)
$Client = [PSCustomObject] #{
targetHost = $DigitalSymphonyHost
targetPort = $DigitalSymphonyPort
source = $TargetSqlInstance
sensor = #()
}
$BaseObj | Where-Object {$_.tags -contains "monitor"} | ForEach-Object {
$sensor = $_
# TODO: How are you getting sensorId?
$sensor | Add-Member -Name 'sensorId' -Value 777 -MemberType NoteProperty
$Client.sensor += $sensor
}
ConvertTo-Json #($Client) -Depth 10 | Out-File "$DestinationPath\client-sensors.json" -Force
That will get you the JSON you're looking for.
I have json body in powershell variable and want to get value from it.
Json Body :
"value": [
{
"id": 1,
"scope": "3e93f9e6-f427-48e1-b37b-994d196e1121",
"name": "Default",
"isHosted": false,
"poolType": "automation",
"size": 3
},
{
"id": 2,
"scope": "3e93f9e6-f427-48e1-b37b-994d196e1121",
"name": "Hosted",
"isHosted": true,
"poolType": "automation",
"size": 10
},
{
"id": 4,
"scope": "3e93f9e6-f427-48e1-b37b-994d196e1121",
"name": "Hosted VS2017",
"isHosted": true,
"poolType": "automation",
"size": 10
}]
I want to get the id value where name=Hosted VS2017 i.e 4
powershell :
Write-Host "json body:" $projects
$id = $projects.value | where { $_.name -eq "Hosted VS2017" }
Write-Host "id :" $id
You need to convert your JSON into a powershell object before you can work with it:
$projects = $projects | ConvertFrom-Json
Then you can access its members:
#requires -Version 3
$projects.value | ? name -eq 'Hosted VS2017'