Assign Value To Variable After Extracting From Json File Using Powershell - json

I have the below json file
{
"name": "ca",
"version": "5.2.0"
}
I am extracting the value of version and trying to assign it to a variable ver
$jsonString = Get-Content -Path ./package.json
$jsonObj = $jsonString | ConvertFrom-Json
echo $jsonObj.version
Write-Host "##vso[task.setvariable variable=ver]$jsonObj.version"
echo $ver
Below is the output
5.2.0
I am expecting the value to be printed twice and also get it assigned to the variable ver but it is not getting assigned

If you are trying to use it in builds, you will not see a new value in the same step. Additionally, use $($jsonObj.version) in the logging command:
steps:
- powershell: |
$jsonString = Get-Content -Path ./package.json
$jsonObj = $jsonString | ConvertFrom-Json
$jsonObj.version
Write-Host "##vso[task.setvariable variable=my.ver]$($jsonObj.version)"
displayName: 'Set vars'
- powershell: |
$ver = '$(my.ver)'
$ver
displayName: 'Read vars'

Related

How to overcome WARNING: Resulting JSON is truncated as serialization has exceeded the set depth of 2?

I have provided my code and JSON format below. I'm using Powershell runbook to retrieve the values from this json. But I am facing error. How can I fix it?
My JSON:
{"hunting": [
{
"displayName":"New Changes made to AWS IAM policy",
"description":"test",
"query":"SecurityEvent | where EventID == \"4687\" | where CommandLine contains \"-noni -ep bypass $\"",
"tactics":["Persistence","LateralMovement","Collection"]
},{
"displayName":"New Consent to Application discovery",
"description":"test",
"query":"SecurityEvent | where EventID == \"4688\" | where CommandLine contains \"-noni -ep bypass $\"",
"tactics":["Persistence","LateralMovement"]
}
]}
My code:
Get-AzStorageBlobContent -Destination $outPath -Container $containerName -Blob $huntingQueryFileName -Context $storageContext -Force
$newHuntingRules = Get-Content -Path "$outPath\$huntingQueryFileName" -Raw | ConvertFrom-Json
Facing the below error:
WARNING: Resulting JSON is truncated as serialization has exceeded the set depth of 2
I executed below script in my environment and was able to successfully retrieve the expected content (from json format).
$path = "C:\temp"
$context = New-AzStorageContext -StorageAccountName "jahnavistorage" -StorageAccountKey "<storageaccountkey>=="
Get-AzStorageBlobContent -Container "<containerName>" -Blob "myjson.json" -Destination $path -context $context
Get-ChildItem -path $path
Get-Content -Raw $path\myjson.json | ConvertFrom-Json
Output:

Unable to convert Yaml to Powershell Object

Above is variables.stg.yml
I am trying to read it in my Powershell code. I used https://www.powershellgallery.com/packages/powershell-yaml/0.4.2 for this
$os_list = (Get-Content -Raw -Path ..\variables.stg.yml| ConvertFrom-Yaml)
$json = $os_list | ConvertTo-Json
Write-Host $json
#Convert JSON file to an object
$JsonParameters = ConvertFrom-Json -InputObject $json
Write-Host $JsonParameters
#Create new PSObject with no properties
$oData = New-Object PSObject
#Loop through properties of the $JsonParameters.parameters object, and add them to the new blank object
$JsonParameters.parameters.psobject.Properties.Name |
ForEach{
Add-Member -InputObject $oData -NotePropertyName $_ -NotePropertyValue
$JsonParameters.parameters.$_.Value
}
Write-Host $oData
However what i see is :
The immediate problem with your code is that you're referencing $JsonParameter.parameters when you really want $JsonParameters.variables - the property name in the yaml file is variables, not parameters.
A less cumbersome way to obtain an object with the ABC and Test entries from the yaml file as properties would be to simply cast the hashtable generated by ConvertTo-Yaml to a [PSCustomObject]:
$documentWithVariables = Get-Content -Path ..\variables.stg.yml -Raw |ConvertFrom-Yaml
$oData = [PSCustomObject]$documentWithVariables.variables
Much simpler :)
It seems like you're trying to use Convertto-YAML to converted to serialized JSON.
Accordding to their documentation you need to use the jsoncompatible flag to do this.
Converting from YAML to JSON
The awesome YamlDotNet assembly allows us to serialize an object in a
JSON compatible way. Unfortunately it does not support indentation.
Here is a simple example:
Import-Module powershell-yaml
PS C:\> $yaml = #"
anArray:
- 1
- 2
- 3
nested:
array:
- this
- is
- an
- array
hello: world
"#
PS C:\> $obj = ConvertFrom-Yaml $yaml
PS C:\> $obj
Name Value
---- -----
anArray {1, 2, 3}
nested {array}
hello world
PS C:\> ConvertTo-Yaml -JsonCompatible $obj
{"anArray": [1, 2, 3], "nested": {"array": ["this", "is", "an", "array"]}, "hello": "world"}
# Or you could do it in one line.
PS C:\> ConvertFrom-Yaml $yaml | ConvertTo-Yaml -JsonCompatible
{"anArray": [1, 2, 3], "nested": {"array": ["this", "is", "an", "array"]}, "hello": "world"}
Your array is also not formatted correctly to be imported as a nested. Below is correct syntax:
variables:
ABC:
XYz
Test:
preprod01
Finally:
[pscustomobject]$os_list = (ConvertFrom-Yaml -yaml (get-content -Raw C:\Powershell\TestCSVs\variables.stg.yml))
[pscustomobject]$os_list = ConvertTo-Yaml $os_list -JsonCompatible
$os_list
$oData = $os_list.variables
$oData
PS:> {"variables": {"ABC": "XYz", "Test": "preprod01"}}

How to pass Json parameters to powershell script

I would like to pass Json data to Powershell script.
PowerShell script:
Get-AzMySqlFirewallRule -ResourceGroupName "dev" -ServerName "dev-DB-Server" | Out-File "file.json"
New-AzMySqlFirewallRule -Name “” -ResourceGroupName "dev" -ServerName "dev-core" -EndIPAddress "" -StartIPAddress ""
In the above powershell script I need to get values to "" from Json file mentioned below.So how to get Json parameter values during run time and all 3 parameters should be passed to the above command and so that it will create new firewall rule to new DB server.
Also, when I run the powershell command (Get-AzMySqlFirewallRule -ResourceGroupName "dev" -ServerName "dev-DB-Server" | Out-File "file.json") I am getting my Json file data in the below format.Not sure whether this format looks good but I need the below values start from pdbr_home,1.2.3.4 and 5.6.7.8 and similarly another 2 rows of data should be passed to my powershell command here New-AzMySqlFirewallRule -Name “” -ResourceGroupName "dev" -ServerName "dev-core" -EndIPAddress "" -StartIPAddress "". via for loop.
file.Json:
[
{
"EndIPAddress": "1.3.2.2",
"Id": "/subscriptions/abcdefg/resourceGroups/dev/providers/Microsoft.DBforMySQL/servers/db-dev- vm/firewallRules/praveen_Home",
"Name": "praveen_Home",
"StartIPAddress": "4.3.1.2",
"Type": "Microsoft.DBforMySQL/servers/firewallRules"
},
{
"EndIPAddress": "2.4.5.6",
"Id": "/subscriptions/abcdefg/resourceGroups/dev/providers/Microsoft.DBforMySQL/servers/db-dev- vm/firewallRules/pdbr_Home",
"Name": "pdbr_Home",
"StartIPAddress": "3.2.1.2",
"Type": "Microsoft.DBforMySQL/servers/firewallRules"
}
]
The below command output as follows.
PS /home/praveen> Get-Command json
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet ConvertFrom-Json 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet ConvertTo-Json 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Test-Json 7.0.0.0 Microsoft.PowerShell.Utility
Application json_pp 0.0.0.0 /usr/bin/json_pp
Application json_pp 0.0.0.0 /bin/json_pp
Error:
Error:
New-AzMySqlFirewallRule: /home/praveen/dbtest.ps1:21
Line |
21 | … -ServerName "praveen-dev" -EndIPAddress $entry.EndIPAddress -StartI …
| ~~~~~~~~~~~~~~~~~~~
| Cannot bind argument to parameter 'EndIPAddress' because it is an empty string.
Final solution worked for me now:
##################### Updating Firewall rules from Soiurce DB server to Target DB server ##################
Write-Host -NoNewline "Updating Firewall rules from Soiurce DB server to Target DB server"
Get-AzMySqlFirewallRule -ResourceGroupName $ResourceGroupName -ServerName $SourceDBServerName | Select-Object Name, StartIPaddress, EndIPaddress | Convertto-Json | Out-File "firewallrule.json"
foreach ($frule in (Get-Content firewallrule.json -raw | ConvertFrom-Json)) {
New-AzMySqlFirewallRule -Name $frule.Name -ResourceGroupName $ResourceGroupName -ServerName $TargetDBServerName -EndIPAddress $frule.EndIPAddress -StartIPAddress $frule.StartIPAddress
}
Use Convertto-Json before writing file.
Docs: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json?view=powershell-7.2
Get-AzMySqlFirewallRule -ResourceGroupName "dev" -ServerName "dev-DB-Server" | Convertto-Json | Out-File "file.json"
EDIT as requested:
Get-AzMySqlFirewallRule -ResourceGroupName "dev" -ServerName "dev-DB-Server" | Select-Object Name,"StartIP address", "EndIP address"| Convertto-Json | Out-File "file.json"
Another EDIT as requested (fixed my mistake - thank you #sage pourpre):
foreach ($entry in (Get-Content file.json -raw | ConvertFrom-Json) {
New-AzMySqlFirewallRule -name $entry.Name `
-ResourceGroupName "dev" `
-ServerName "dev-core" `
-StartIPAddress $entry.StartIPAddress `
-EndIPAddress $entry.EndIPAddress
}
try the below:
Get-AzMySqlFirewallRule -ResourceGroupName "dev" -ServerName "dev-DB-Server" | Convertto-Json | Out-File "file.json"
$data = Get-Content "C:\Users\me\file.json" | Out-String | ConvertFrom-Json #replace path to where you have exported the json file
foreach ($line in $data) {
New-AzMySqlFirewallRule -name $line.Name `
-ResourceGroupName "dev" `
-ServerName "dev-core" `
-StartIPAddress $line.StartIPAddress `
-EndIPAddress $line.EndIPAddress
}
A different method, although the question is for JSON, would be to just store the rules in a variable.
$rules = Get-AzMySqlFirewallRule -ResourceGroupName "dev" -ServerName "dev-DB-Server"
foreach ($rule in $rules){
New-AzMySqlFirewallRule -name $rule.Name `
-ResourceGroupName "dev" `
-ServerName "dev-core" `
-StartIPAddress $rule.StartIPAddress `
-EndIPAddress $rule.EndIPAddress
}
I was able to fix this solution with help of all the above inputs few days ago. Thanks to all.Really appreciated your help.
Updating Firewall rules from Source DB server to Target DB server
Write-Host -NoNewline "Updating Firewall rules from Soiurce DB server to Target DB server"
Get-AzMySqlFirewallRule -ResourceGroupName $ResourceGroupName -ServerName $SourceDBServerName | Select-Object Name, StartIPaddress, EndIPaddress | Convertto-Json | Out-File "firewallrule.json"
foreach ($frule in (Get-Content firewallrule.json -raw | ConvertFrom-Json)) {
New-AzMySqlFirewallRule -Name $frule.Name -ResourceGroupName $ResourceGroupName -ServerName $TargetDBServerName -EndIPAddress $frule.EndIPAddress -StartIPAddress $frule.StartIPAddress
}
//role-definition.json
{
"RoleName": "MyReadWriteRole",
"Type": "CustomRole",
"AssignableScopes": ["/"],
"Permissions": [{
"DataActions": [
"Microsoft.DocumentDB/databaseAccounts/readMetadata",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*"
]
}]
}
Coverting it into json object as i need to pass it as an argument in a powershell parameter.
So i did below -
Created a powershell parameter
$roleDef= #"
{
"RoleName": "MyReadWriteRole",
"Type": "CustomRole",
"AssignableScopes": ["/"],
"Permissions": [{
"DataActions": [
"Microsoft.DocumentDB/databaseAccounts/readMetadata",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/"
]
}]
}
"#
$jsonObject = $roleDef | ConvertFrom-Json
az cosmosdb sql role definition create --account-name cosmosdbaccname --resource-group 'my-rg' --body $jsonObject
but I get below error -
Failed to parse string as JSON:
#{RoleName=MyReadWriteRole; Type=CustomRole; AssignableScopes=System.Object[]; Permissions=System.Object[]}
Error detail: Expecting value: line 1 column 1 (char 0)

Find and Replace Nested JSON Values with Powershell

I have an appsettings.json file that I would like to transform with a PowerShell script in a VSTS release pipeline PowerShell task. (BTW I'm deploying a netstandard 2 Api to IIS). The JSON is structured like the following:
{
"Foo": {
"BaseUrl": "http://foo.url.com",
"UrlKey": "12345"
},
"Bar": {
"BaseUrl": "http://bar.url.com"
},
"Blee": {
"BaseUrl": "http://blee.url.com"
}
}
I want to replace BaseUrl and, if it exists, the UrlKey values in each section which are Foo, Bar and Blee. (Foo:BaseUrl, Foo:UrlKey, Bar:BaseUrl, etc.)
I'm using the following JSON structure to hold the new values:
{
"##{FooUrl}":"$(FooUrl)",
"##{FooUrlKey}":"$(FooUrlKey)",
"##{BarUrl}":"$(BarUrl)",
"##{BleeUrl}":"$(BleeUrl)"
}
So far I have the following script:
# Get file path
$filePath = "C:\mywebsite\appsettings.json"
# Parse JSON object from string
$jsonString = "$(MyReplacementVariablesJson)"
$jsonObject = ConvertFrom-Json $jsonString
# Convert JSON replacement variables object to HashTable
$hashTable = #{}
foreach ($property in $jsonObject.PSObject.Properties) {
$hashTable[$property.Name] = $property.Value
}
# Here's where I need some help
# Perform variable replacements
foreach ($key in $hashTable.Keys) {
$sourceFile = Get-Content $filePath
$sourceFile -replace $key, $hashTable[$key] | Set-Content $filePath
Write-Host 'Replaced key' $key 'with value' $hashTable[$key] 'in' $filePath
}
Why are you defining your replacement values as a JSON string? That's just going to make your life more miserable. If you're defining the values in your script anyway just define them as hashtables right away:
$newUrls = #{
'Foo' = 'http://newfoo.example.com'
'Bar' = 'http://newbaz.example.com'
'Blee' = 'http://newblee.example.com'
}
$newKeys = #{
'Foo' = '67890'
}
Even if you wanted to read them from a file you could make that file a PowerShell script containing those hashtables and dot-source it. Or at least define the values as lists of key=value lines in text files, which can easily be turned into hashtables:
$newUrls = Get-Content 'new_urls.txt' | Out-String | ConvertFrom-StringData
$newKeys = Get-Content 'new_keys.txt' | Out-String | ConvertFrom-StringData
Then iterate over the top-level properties of your input JSON data and replace the nested properties with the new values:
$json = Get-Content $filePath | Out-String | ConvertFrom-Json
foreach ($name in $json.PSObject.Properties) {
$json.$name.BaseUrl = $newUrls[$name]
if ($newKeys.ContainsKey($name)) {
$json.$name.UrlKey = $newKeys[$name]
}
}
$json | ConvertTo-Json | Set-Content $filePath
Note that if your actual JSON data has more than 2 levels of hierarchy you'll need to tell ConvertTo-Json via the parameter -Depth how many levels it's supposed to convert.
Side note: piping the Get-Content output through Out-String is required because ConvertFrom-Json expects JSON input as a single string, and using Out-String makes the code work with all PowerShell versions. If you have PowerShell v3 or newer you can simplify the code a little by replacing Get-Content | Out-String with Get-Content -Raw.
Thank you, Ansgar for your detailed answer, which helped me a great deal. Ultimately, after having no luck iterating over the top-level properties of my input JSON data, I settled on the following code:
$json = (Get-Content -Path $filePath) | ConvertFrom-Json
$json.Foo.BaseUrl = $newUrls["Foo"]
$json.Bar.BaseUrl = $newUrls["Bar"]
$json.Blee.BaseUrl = $newUrls["Blee"]
$json.Foo.Key = $newKeys["Foo"]
$json | ConvertTo-Json | Set-Content $filePath
I hope this can help someone else.
To update values of keys at varying depth in the json/config file, you can pass in the key name using "." between the levels, e.g. AppSettings.Setting.Third to represent:
{
AppSettings = {
Setting = {
Third = "value I want to update"
}
}
}
To set the value for multiple settings, you can do something like this:
$file = "c:\temp\appSettings.json"
# define keys and values in hash table
$settings = #{
"AppSettings.SettingOne" = "1st value"
"AppSettings.SettingTwo" = "2nd value"
"AppSettings.SettingThree" = "3rd value"
"AppSettings.SettingThree.A" = "A under 3rd"
"AppSettings.SettingThree.B" = "B under 3rd"
"AppSettings.SettingThree.B.X" = "Z under B under 3rd"
"AppSettings.SettingThree.B.Y" = "Y under B under 3rd"
}
# read config file
$data = Get-Content $file -Raw | ConvertFrom-Json
# loop through settings
$settings.GetEnumerator() | ForEach-Object {
$key = $_.Key
$value = $_.Value
$command = "`$data.$key = $value"
Write-Verbose $command
# update value of object property
Invoke-Expression -Command $command
}
$data | ConvertTo-Json -Depth 10 | Out-File $file -Encoding "UTF8"

Access Object From JSON File in Powershell

I have a JSON file that I am reading in Powershell. The structure of the file is below.
[
["computer1", ["program1", versionX]],
["computer2", ["program2", versionY]],
["computer3", ["program3", "versionX"],
["program1", "versionZ"]
],
]
What I want in the program is use $env:computername and compare it with the computerX in the JSON file. If found a match, then iterate through and get the values of programName and ProgramVersion.
However, I don't know how to search through the objects and find ALL items under that.
This is what I have so far.
$rawData = Get-Content -Raw -Path "file.json" | ConvertFrom-Json
$computername=$env:computername
$data = $rawData -match $computername
This gives me objects under it. But how do I iterate through and get individual values?
But don't know what I do after that.
To start you need to be using a valid JSON file
{
"computer1": {
"program1": "versionX"
},
"computer2": {
"program2": "versionY"
},
"computer3": {
"program3": "versionX",
"program1": "versionZ"
}
}
Then you can access the PSObject Properties
$rawData = Get-Content -Raw -Path "file.json" | ConvertFrom-Json
$rawData.PsObject.Properties |
Select-Object -ExpandProperty Name |
ForEach-Object { IF ($_ -eq $env:COMPUTERNAME) {
Write-Host "Computer Name : " $_
Write-Host "Value : " $rawData."$_"
}
}
EDIT for Computer, Program, and Version as separate values
psobject.Properties.Name will give all the program names.
psobject.Properties.Name[0] will give the first program name.
psobject.Properties.value[0] will give the first program version value.
You need to increment the value to get second value, you can also use -1 as a shortcut for the last value.
$rawData = Get-Content -Raw -Path "file.json" | ConvertFrom-Json
$rawData.PsObject.Properties |
Select-Object -ExpandProperty Name |
ForEach-Object { IF ($_ -eq $env:COMPUTERNAME) {
$Computer = $_
$Values = $rawData.$_
}
}
$Computer
$Values.psobject.Properties
$Values.psobject.Properties.Name
$Values.psobject.Properties.Name[0]
$Values.psobject.Properties.value[0]
$Values.psobject.Properties.Name[1]
$Values.psobject.Properties.value[1]
You could also use the program name
$Values.program1
$Values.program2
$Values.program3