Get value by the array element name in json - json

I'm not sure how to name these elements properly, it'll be easier just to show it. I have following JSON:
{
"DEV": [
{
"GitEmail": "asd#asd.com"
}
],
"TEST": [
{
"GitEmail": "asd1#asd.com"
}
],
"PROD": [
{
"GitEmail": "asd2#asd.com"
}
]
}
I would like to get the "DEV" by providing it's email. How to implement that in powershell?

Something like below can help -
PS> $json = '{
"DEV": [
{
"GitEmail": "asd#asd.com"
}
],
"TEST": [
{
"GitEmail": "asd1#asd.com"
}
],
"PROD": [
{
"GitEmail": "asd2#asd.com"
}
]
}' | ConvertFrom-Json
PS> ($json.psobject.Properties | ? {$_.Value -match "asd#asd.com"}).Name
Depending on the email matches you can retrieve the environment names.

I can't promise there is an easier method, but this here is one way:
Given that you json is stored in a variable $json:
You can get every head object with $json.psobject.properties.name:
Input:
$json.psobject.properties.name
Output:
DEV
TEST
PROD
With this we can create a foreach loop and search for the Email:
foreach ($dev in $json.psobject.properties.name)
{
if($json.$dev.GitEmail -eq "asd#asd.com") {
echo $dev
}
}

I do not know any elegant way of doing it. ConvertFrom-Json does not create neat objects with easy ways to traverse them like convertfrom-xml, instead result is just a PsObject with bunch of noteproperties.
What I do in such cases is
$a= #"
{
"DEV": [
{
"GitEmail": "asd#asd.com"
}
],
"TEST": [
{
"GitEmail": "asd1#asd.com"
}
],
"PROD": [
{
"GitEmail": "asd2#asd.com"
}
]
}
"#
$JsonObject= ConvertFrom-Json -InputObject $a
$NAMES= $JsonObject|Get-Member |WHERE MemberType -EQ NOTEPROPERTY
$NAMES|Foreach-Object {IF($JsonObject.$($_.NAME).GITEMAIL -EQ 'asd#asd.com'){$_.NAME}}
Result of above is
DEV
Not pretty, not really re-usable but works.
If anyone knows a better way of going about it - I'll be happy to learn it:)

Related

Parse a JSON File for values

I have a packer file, for which im trying to parse so i can get the specific scripts, for example in file below just want any mysql in my results e.g. install-mysql.sh, init-mysql.sh
(trying to use powershell for this).
{
"variables": {
"image_iso": "",
"image_sum": ""
},
"builders": [
{
"type": "virtualbox-iso",
"vm_name": "box",
"boot_wait": "10s",
"disk_size": 51200,
"guest_os_type": "RedHat_64"
}
],
"provisioners": [
{
"type": "shell",
"scripts": [
"packer/provisioners/common/base.sh",
"packer/provisioners/common/tcp-kernel-param.sh",
"packer/provisioners/web/create-user-webmaster.sh",
"packer/provisioners/web/install-nginx.sh",
"packer/provisioners/web/advanced-nginx.sh",
"packer/provisioners/web/configure-vhost.sh",
"packer/provisioners/mysql/mysql-kernel-param.sh",
"packer/provisioners/mysql/install-mysql.sh",
"packer/provisioners/mysql/init-mysql.sh",
"packer/provisioners/redis/install-redis.sh",
"packer/provisioners/redis/redis-kernel-param.sh",
"packer/provisioners/misc/install-wandisco-git.sh",
"packer/provisioners/misc/install-chrony.sh",
"packer/provisioners/rails/install-required_package.sh",
"packer/provisioners/rails/install-rbenv.sh",
"packer/provisioners/common/enable-defence-portscan.sh",
"packer/provisioners/common/vagrant.sh",
"packer/provisioners/common/vmware.sh",
"packer/provisioners/common/cleanup.sh"
],
"override": {
"virtualbox-iso": {
"execute_command": "echo 'vagrant'|sudo -S sh '{{.Path}}'"
}
}
},
{
"type": "shell",
"script": "packer/provisioners/common/virtualbox.sh",
"only": [
"virtualbox-iso"
],
"override": {
"virtualbox-iso": {
"execute_command": "echo 'vagrant'|sudo -S sh '{{.Path}}'"
}
}
}
],
"post-processors": [
{
"keep_input_artifact": false,
"type": "vagrant",
"output": "./packer/vagrant-boxes/CentOS-7-x86_64-Minimal.box"
}
]
}
Ive currently parsed this file using powershell
$jsonfile = Get-Content -Raw .\software.json | ConvertFrom-Json
write-output $jsonfile.provisioners.scripts
packer/provisioners/common/base.sh
packer/provisioners/common/tcp-kernel-param.sh
packer/provisioners/web/create-user-webmaster.sh
packer/provisioners/web/install-nginx.sh
packer/provisioners/web/advanced-nginx.sh
packer/provisioners/web/configure-vhost.sh
packer/provisioners/mysql/mysql-kernel-param.sh
packer/provisioners/mysql/install-mysql.sh
packer/provisioners/mysql/init-mysql.sh
packer/provisioners/redis/install-redis.sh
packer/provisioners/redis/redis-kernel-param.sh
packer/provisioners/misc/install-wandisco-git.sh
Im unsure in powershell how to now parse the output above to get just the files i mentioned in the question i.e.
sqlFiles
---------------
install-mysql.sh
init-mysql.sh
Use the Where-Object cmdlet to filter the list:
$mysqlScripts = $jsonfile.provisioners.scripts |Where-Object {$_ -match 'mysql'}
If you want to remove the leading path, use Split-Path -Leaf:
$mysqlScripts |Split-Path -Leaf

How do I add a JSON element if and only if it does not already exist, using Powershell?

I have a JSON file I need to edit, conditionally. It may be an empty object:
{}
or it may contain other data.
I need to see if the data I'd like to add already exists, and if not, add it to that JSON file.
The content in question looks like this (entire JSON file):
{
{
"2020.3.19f1": {
"version": "2020.3.19f1",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2020.3.19f1\\Editor\\Unity.exe"
],
"manual": true
}
}
In this case, if "2020.3.19f" does not exist, I need to add that block.
I looked at these docs but really, lost. Any tips appreciated: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json?view=powershell-7.2
This seems close but I'm lost on the syntax of checking for null or empty, and how that translates to PS: PowerShell : retrieve JSON object by field value
Edit: So, for example if the original file is:
{}
Then I need to overwrite that file with:
{
{
"2020.3.19f1": {
"version": "2020.3.19f1",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2020.3.19f1\\Editor\\Unity.exe"
],
"manual": true
}
}
And if the file already contained something, I need to keep that, just add the new block:
{
{
"2019.4.13f1": {
"version": "2019.4.13f1",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2019.3.13f1\\Editor\\Unity.exe"
],
"manual": true
},
{
"2020.3.19f1": {
"version": "2020.3.19f1",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2020.3.19f1\\Editor\\Unity.exe"
],
"manual": true
}
}
FWIW: I did find the condition I need:
$FileContent = Get-Content -Path "C:\Users\me\AppData\Roaming\UnityHub\editors.json" -Raw | ConvertFrom-Json
if ( ($FileContent | Get-Member -MemberType NoteProperty -Name "2020.3.19f1") -ne $null )
{
echo "it exists"
}
else
{
echo "add it"
# DO SOMETHING HERE TO CREATE AND (OVER)WRITE THE FILE
}
You can convert the json as object and add properties as you want.
$json = #"
{
"2020.3.19f2": {
"version": "2020.3.19f2",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2020.3.19f2\\Editor\\Unity.exe"
],
"manual": true
}
}
"#
$obj = ConvertFrom-Json $json
if (-not $obj.'2020.3.19f1') {
Add-Member -InputObject $obj -MemberType NoteProperty -Name '2020.3.19f1' -Value $(
New-Object PSObject -Property $([ordered]#{
version = "2020.3.19f1"
location = #("C:\Program Files\Unity\Hub\Editor\2020.3.19f1\Editor\Unity.exe")
manual = $true
})
) -Force
$obj | ConvertTo-Json
}

How to modify Json using Powershell

I have the following JSON held in a file "test.json":
{
"metadata": [
{
"src": [
{
"files": [
"src/**.csproj"
]
}
],
"dest": "api",
"disableGitFeatures": false,
"disableDefaultFilter": false
}
]
}
I'd like to modify the "src" element. Instead of:
"src": [
{
"files": [
"src/**.csproj"
]
}
],
It needs to be:
"src": [
{
"files": [
"*.csproj"
],
"cwd":".."
}
],
Where I modify the first element of "files" and add "cwd". This should be straight forward but I'm struggling to achieve this in powershell. Can anyone point me in the right direction of any examples of this?
Thanks for any pointers in advance.
You can do the following:
$JSONObject = Get-Content test.json -Raw | ConvertFrom-Json
$JSONObject.metadata.src.files = ,'*.csproj'
$JSONObject.metadata.src | Add-Member -Name 'cwd' -Value '..' -MemberType NoteProperty
$JSONObject | ConvertTo-Json -Depth 5 | Set-Content test.json
The tricky part is to make sure the .files value is an array of a single element. You can do this with the array subexpression operator #() or the unary operator ,.

Access Properties and Keys within JSON using PowerShell

I have a PowerShell script and would like to access a nested key. Here is my JSON:
{
"name": "versions.json",
"versions": {
"1.0.0": {
"Component1": "1.0.0",
"Component2": "1.0.0",
"Component3": "1.0.0"
},
"2.0.0": {
"Component1": "2.0.0",
"Component2": "2.0.0",
"Component3": "2.0.0"
}
}
}
I'm unsure of how to access the values within each version (1.0.0 and 2.0.0). I know I get the property name for each "version" by using:
($json.versions.PSobject.Properties) | ForEach-Object {
"Data: $($_.Name)"
}
But how do I iterate through each of a "version" objects properties and view its value, i.e. how do I check what is contained within "1.0.0"? For "1.0.0" I would expect to see
"Component1" at 1.0.0
"Component2" at 1.0.0
"Component3" at 1.0.0
Do the same you're doing for versions for the values of its properties:
$json.versions.PSobject.Properties | ForEach-Object {
"Data: $($_.Name)"
$_.Value.PSobject.Properties | ForEach-Object {
'"{0}" at {1}' -f $_.Name, $_.Value
}
}

Editing a .json file using powershell

I have a .json file that needs to be edited in User Data, so I will have to use powershell to accomplish this.
The json looks something like this:
{
"EngineConfiguration": {
"PollInterval": "00:00:15",
"Components": [
{
"Id": "CustomLogs",
"FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
"Parameters": {
"LogDirectoryPath": "C:\\CustomLogs\\",
"TimestampFormat": "MM/dd/yyyy HH:mm:ss",
"Encoding": "UTF-8",
"Filter": "",
"CultureName": "en-US",
"TimeZoneKind": "Local"
}
}
],
"Flows": {
"Flows":
[
"(ApplicationEventLog,SystemEventLog),CloudWatchLogs"
]
}
}
}
I would like it to look like this --
{
"EngineConfiguration": {
"PollInterval": "00:00:15",
"Components": [
{
"Id": "CustomLogs",
"FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
"Parameters": {
"LogDirectoryPath": "C:\\ProgramData\\Amazon\\CodeDeploy\\deployment-logs",
"TimestampFormat": "[yyyy-MM-dd HH:mm:ss.fff]",
"Encoding": "UTF-8",
"Filter": "",
"CultureName": "en-US",
"TimeZoneKind": "Local"
}
}
],
"Flows": {
"Flows":
[
"(ApplicationEventLog,SystemEventLog, CustomLogs),CloudWatchLogs"
]
}
}
}
In the Custom Logs Parameters, the LogDirectoryPath and TimestampFormat have both changed. Also, in the Flows section, I have added the 'CustomLogs' to the CloudWatch Group.
I tried making it work with code like this:
$a = Get-Content 'C:\PATH\TO\file.json' -raw | ConvertFrom-Json
$a.EngineConfiguration.Components[0].Parameters = '{"LogDirectoryPath": "","TimestampFormat": "[yyyy-MM-dd HH:mm:ss.fff]","Encoding": "UTF-8","Filter": "","CultureName": "en-US","TimeZoneKind": "Local"}'
$a | ConvertTo-Json | set-content 'C:\PATH\TO\output.json'
But that produces a very ugly output
{
"EngineConfiguration": {
"PollInterval": "00:00:15",
"Components": [
"#{Id=CustomLogs; FullName=AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch; Parameters={\"LogDirectoryPath\": \"\",\"TimestampFormat\": \"[yyyy-MM-dd HH:mm:ss.fff]\",\"Encoding\": \"UTF-8\",\"Filter\": \"\",\"CultureName\": \"en-US\",\"TimeZoneKind\": \"Local\"}}",
"#{Id=CloudWatchLogs; FullName=AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch; Parameters=}"
],
"Flows": {
"Flows": "(ApplicationEventLog,SystemEventLog),CloudWatchLogs"
}
}
}
Is there a more elegant way to do this? Any advice would be greatly appreciated. Thanks!
Try using the -Depth switch for ConvertTo-Json. By default this compresses any child elements beyond a depth of 2 to the string representations of the object you have seen:
"#{Id=CustomLogs; etc."
By specifying a deeper depth you get a format more like the one you want. Combine this with something that compresses the excessive whitespace as so:
((ConvertFrom-Json $a) | ConvertTo-Json -Depth 4) -replace ((" "*4)," ")
It would be possible to reduce the leading whitespace with a regex. However, that does not really produce the reformatting, pretty-print that you say you want.
$a | ConvertTo-Json | % {$_ -replace " "," "} | set-content 'output.json'