How can we create dynamic json object in powershell - json

I am creating powershell script which generation json file where i want to create json object runtime based on mentioned name in $env variable and put some value inside it as json.
$env="prd,test,dev,..,...." # there are total 15 env & $env has 1 and more env.
Desire JSON :
{
"prd" : {
"Sid": "xxxxxx" }
"test" : {
"Sid": "xxx" }
"So on" : {}
}
Trying to write script:
$env="prd,test,..,...,.."
$env=$env - split ","
For ( $i = 0 $i -le ($env.length -1) ;$i+=1){
$env[$i] = New-object System.Collection.ArrayList
$env[$i].add("anydata10")
}
But this approach not working well since $env variable has any 1 or more env value.
In the powershell, can we create dynamic json object at runtime and any other approch to archive it ?

For the root-level object ({"prd":{...}, "test":{...}}), I'd suggest an ordered dictionary, then create a custom object with the Sid property for each property:
# prepare env keys
$environments = "prd,test,dev,stg,qa" -split ","
# create ordered dictionary
$jsonObject = [ordered]#{}
foreach($envName in $environments){
# create 1 property, the value of which will be an object with a `Sid` property
$jsonObject[$envName] = [pscustomobject]#{
# resolve the correct `Sid` value from somewhere
Sid = Get-SidForEnv $envName
}
}
# convert the whole thing to json
$jsonObject |ConvertTo-Json -Depth 3
Based on your comments about getting the correct sid value "from somewhere", I assume you already have a function that translates prd to prodsid1 and so forth, so simply replace Get-SidForEnv with whatever function that is :)

I'm not sure I understand what you're trying to achieve. You can access environment variables using $env. So, if you have those values prd,test,... in some environment variable and you want to generate new environment variables based on those, you can do it like this:
# $env:foo contains 'prd,test'
$env:foo -split ',' | % {
New-Item -Path Env: -Name $_ -Value (#("anydata10") | ConvertTo-Json)
}

Related

I want to create json file by substituting values from environment variables in a json template file

One requirement of mine is - Using windows, not use any tools not already available as part of aws cli or windows
For example, I have this json file test.json with below content:
"My number is $myvar"
I read this into a powershell variable like so:
$myobj=(get-content .\test.json | convertfrom-json)
$myvar=1
From here, I would like to do something with this $myobj which will enable me to get this output:
$myobj | tee json_with_values_from_environment.json
My number is 1
I got some limited success with iex, but not sure if it can be made to work for this example
You can use $ExecutionContext.InvokeCommand.ExpandString()
$myobj = '{test: "My number is $myvar"}' | ConvertFrom-Json
$myvar = 1
$ExecutionContext.InvokeCommand.ExpandString($myobj.test)
Output
My number is 1
Here is one way to do it using the Parser to find all VariableExpressionAst and replace them with the values in your session.
Given the following test.json:
{
"test1": "My number is $myvar",
"test2": {
"somevalue": "$env:myothervar",
"someothervalue": "$anothervar !!"
}
}
We want to find and replace $myvar, $myothervar and $anothervar with their corresponding values defined in the current session, so the code looks like this (note that we do the replacement before converting the Json string into an object, this way is much easier):
using namespace System.Management.Automation.Language
$isCore7 = $PSVersionTable.PSVersion -ge '7.2'
# Define the variables here
$myvar = 10
$env:myothervar = 'hello'
$anothervar = 'world'
# Read the Json
$json = Get-Content .\test.json -Raw
# Now parse it
$ast = [Parser]::ParseInput($json, [ref] $null, [ref] $null)
# Find all variables in it, and enumerate them
$ast.FindAll({ $args[0] -is [VariableExpressionAst] }, $true) |
Sort-Object { $_.Extent.Text } -Unique | ForEach-Object {
# now replace the text with the actual value
if($isCore7) {
# in PowerShell Core is very easy
$json = $json.Replace($_.Extent.Text, $_.SafeGetValue($true))
return
}
# in Windows PowerShell not so much
$varText = $_.Extent.Text
$varPath = $_.VariablePath
# find the value of the var (here we use the path)
$value = $ExecutionContext.SessionState.PSVariable.GetValue($varPath.UserPath)
if($varPath.IsDriveQualified) {
$value = $ExecutionContext.SessionState.InvokeProvider.Item.Get($varPath.UserPath).Value
}
# now replace the text with the actual value
$json = $json.Replace($varText, $value)
}
# now we can safely convert the string to an object
$json | ConvertFrom-Json
If we were to convert it back to Json to see the result:
{
"test1": "My number is 10",
"test2": {
"somevalue": "hello",
"someothervalue": "world !!"
}
}

PowerShell: How can I output a hashtable as json and store it in a variable using a foreach loop?

I'm trying to write a script that interacts with a Rest API to make changes in active directory (I know that doesn't make a lot of sense, but it's how our company does things). The change is to modify the homeDirectory attribute of a list of users belonging to a specific security group. The user's aren't all in the same domain, but are in the same forest and are registered in the global catalog.
So far, this is what I have that works:
function get-groupusers{
$memberlist = get-adgroup -filter "name -eq 'group.users'" -server "server.domain.com" -property member |select -expandproperty member
$GlobalCatalog = Get-ADDomainController -Discover -Service GlobalCatalog
foreach ($member in $memberlist){
get-aduser -identity $member -server "$($GlobalCatalog.name):3268"
}
}
$sAMAccountName = (get-groupusers).samaccountname
This is the part I'm running into problems with:
foreach($an in $SamAccountName){
$json = #{
input = #{
key = "homeDirectory"
value = "\\filepath\$an"
}
}
}
The goal here, is to convert the hashtables into json (the required format for interacting with the API), and save it in the following format (note, the "input" "key" and "value" keys are all what the API actually uses, not just substitutions):
{
"input":{
"key":"homeDirectory",
"value":"\\\\filepath\\$an"
},
{
"key":"homeDirectory",
"value":"\\\\filepath\\$an"
}
}
But right now, the foreach loop just overwrites the $json variable with the last set of hashtables. The loop is iterating over the list correctly, as I can put a convertto-json|write-host cmdlet in it but then the $an variable outputs as "#(samaccountname="$an") instead of just whatever the $an actually is.
If my guess is right and you want a resulting Json as the one shown in your question (with the exception that, as mclayton stated in comments, the input property value should be wrapped in [...] to be an array) then this should do it:
$json = #{
input = #(
foreach($an in $SamAccountName) {
[ordered]#{
key = "homeDirectory"
value = "\\filepath\$an"
}
}
)
}
$json | ConvertTo-Json -Depth 99

powershell cant get json key / value

Hello I have a json file below:
{
"supports": {},
"dependencies": {
"AST.NxTestware.main": "1.1.0",
"otherPackagenName": "7.7.7"
},
"frameworks": {
".NETPortable,Version=v4.5,Profile=Profile78": {}
}
}
and I am trying to write a .ps1 powershell script that will look at every item under 'dependencies', check if the name matches, and if so, retrieve the version number.
but I am having trouble parsing through each item in 'dependencies', and cannot retrieve the package name string or version number
My ps1 looks like this:
$targetName = "otherPackagenName"
Write-Host "Trying to get version # of $targetName if it exists inside project.json"
# get json file contents
$json = Get-Content .\project.json | ConvertFrom-Json
# retrieve dependencies
$dependencies = $json.dependencies
Write-Host "dependencies = $dependencies"
# iterate through each dependency
foreach ($dep in $dependencies) {
Write-Host "dep = $dep"
# try to get dependency name (attempt1)
$depName1 = $dep[0]
Write-Host "depName1 = $depName1"
# try to get dependency name (attempt2)
$depName2 = $dep.Name
Write-Host "depName2 = $depName2"
if($depName1 -eq $targetName) {
write-host "Found it! now get version number"
} else {
write-host "Did not find our package"
}
}
output shows it correctly retrieves the json key/value pair, but I cant figure out how to retrieve the package name and version number, as every thing ive tried just returns blank:
Trying to get version # of otherPackagenName if it exists inside project.json
dependencies = #{AST.NxTestware.main=1.1.0; otherPackagenName=7.7.7}
dep = #{AST.NxTestware.main=1.1.0; otherPackagenName=7.7.7}
depName1 = #{AST.NxTestware.main=1.1.0; otherPackagenName=7.7.7}
depName2 =
Did not find our package
my dependencies is coming through like so:
#{AST.NxTestware.main=1.1.0; otherPackagenName=7.7.7}
How can I iterate through this object?
How can I retrieve the key ('AST.NxTestware.main') and value ('1.1.0') for each dependency?
I'm guessing you're looking for this:
$json.Dependencies | ForEach-Object {
$prop = $_.PSObject.Properties
[pscustomobject]#{
DependencyName = $prop.Name
Version = [version] $prop.Value
}
}
You can get an object's property Name and property Value by accessing the object's PSObject member, from there you can reference the Properties property of each object.

Add windows env variables to json object using powershell

I'm quite new to powershell and just need it for a small task so please excuse my complete and utter ineptitude for the language. I was wondering if it were possible to form a json object based off environment variables and a variable that has already been declared earlier in my script. The variable that was already declared is based off a json config named optionsConfig.json and the contents of that file are here.
{"test1": ["options_size", "options_connection", "options_object"],
"test2":["options_customArgs", "options_noUDP", "options_noName"]}
The purpose of the $Options variable in the code below is to take each element in the list value for the respective test and assume that those elements are environment variables in the system, then find their values and form a dictionary object that will be used in the json.
Here is what I have so far.
# Read the JSON file into a custom object.
$configObj = Get-Content -Raw optionsConfig.json |
ConvertFrom-Json
# Retrieve the environment variables whose
# names are listed in the $env:test property
# as name-value pairs.
Get-Item -Path env:* -Include $configObj.$env:testTool
$Options = Get-Item -Path env:* -Include $configObj.$env:testTool |
% {$hash = #{}} {$hash[$_.Name]=$_.Value} {$hash}
The $Options variable looks like so when converted to json
{
"options_size": "default",
"options_object": "forward open",
"options_connection": "connected"
}
I have a few other environment variable values that I would like to be a part of the json object. Those 3 other environment variables I would like the value of are listed below.
$Env.testTool = "test1"
$Env.RecordName = "Record1"
$Env.Target = "Target1"
How would I construct a powershell statement to get the json object to be formatted like this? -
data = {"test": $Env.testTool, "target": "$Env.Target",
"options": "$Options", "RecordName': "$Env.RecordName"}
The keys are all predefined strings and $Options is the dict object from up above. Am I able to form a Json object like this in powershell and how would it be done? Any help would be appreciated. This appears to be the last step in my struggle with powershell.
Here is what I have done.
$jObj = [ordered]#{test= $Env:testTool}
When I change this variable to $jObj = [ordered]#{test= $Env:testTool,options= $Options} I get an error saying missing expression after ','
When I change this variable to $jObj = [ordered]#{test= $Env:testTool,options= $Options} I get an error saying missing expression after ','
Entries of a hashtable literal (#{ ... } or, in its ordered form, [ordered] #{ ... }) must be separated:
either by newlines (each entry on its own line)
or by ; if placed on the same line.
Thus, the following literals are equivalent:
# Multiline form
#{
test= $env:testTool
RecordName= $env:RecordName
Target= $env.Target
options=$Options
}
# Single-line form; separator is ";"
#{ test= $env:testTool; RecordName= $env:RecordName; Target= $env.Target; options=$Options }
Get-Help about_Hashtables has more information.
$jObj = #{test= $env:testTool
RecordName= $env:RecordName
Target= $env.Target
options=$Options}
$jObj | ConvertTo-Json | Set-Content jsonStuff.json
JsonStuff.json is the new json file for the new json object. This syntax for forming $jObj seems to have done the trick.

Merging JSON Objects at runtime in Powershell

Following on from a question yesterday (JSON and references to other JSON objects).
Is it possible to merge JSON objects at runtime in a similar fashion?
In my test.json I wish to insert the $Defaults.wimos object into WIMS.wimos at runtime similar to what I did for the $Paths.drive value in $Defaults.
{
Paths: {drive: "W:"},
Defaults: {wimos: {dstdrive: "$($Paths.drive)"}
},
WIMS: {
winos: "$($Defaults.wimos)",
wimre: {dstdrive: "$($Paths.drive)"}
}
}
In the following code I cannot work out the syntax to have the object replaced at runtime.
$JSONConfig="test.json"
$rawJSON = (Get-Content $JSONConfig -Raw)
$pathJSON = $rawJSON | ConvertFrom-Json
#
# Load Paths from JSON into $Paths
#
$Paths=$pathJSON.Paths
#
# Merge JSON objects to have the defaults replaced
#
$DefaultsJSON=($ExecutionContext.InvokeCommand.ExpandString($rawJSON)) | ConvertFrom-Json
#
# Load Defaults into $Defaults
#
$Defaults=$DefaultsJSON.Defaults
#
# Merge JSON objects to have the System replaced
#
$JSON = ($ExecutionContext.InvokeCommand.ExpandString($rawJSON)) | ConvertFrom-Json
$JSON.WIMS
write-host ("JSON.WIMS.wimre.dstdrive =" + $JSON.WIMS.wimre.dstdrive)
write-host ("JSON.WIMS.wimos.dstdrive =" + $JSON.WIMS.wimos.dstdrive) #This fails to access and print "W:"
I would like to be able to replace $($Defaults.wimos) and be able to query the dstdrive member.
Is this possible to achieve this in powershell? Any suggestions on how?
Thanks
Stuart
There's a couple of issues in your code. First, the value that would be inserted into your template would be interpolated as a string and not a json-object.
To do this, you could use the ConvertTo-json within the template. I'll show you how in a minute.
If you're gonna be recreating and using different "templates" within the same file (like path, defaults etc), I would create a helper function for recreating / filling out the template on your session variables all the time (in order to avoid repeating code).
Create the following method:
function Get-ParsedJsonTemplate(){
return ($ExecutionContext.InvokeCommand.ExpandString((Get-Content $JSONConfig -Raw))) | ConvertFrom-Json
}
Change your template json to the following (showing you that you can use powershell code within your template file:
{
Paths: {drive: "W:"},
Defaults: {wimos: {dstdrive: "$($Paths.drive)"}},
WIMS: {
winos: $(
if($Defaults -and $Defaults.wimos){
$Defaults.wimos|ConvertTo-Json -Compress
} else {
#{"dstdrive"=""}|ConvertTo-Json -compress
}
),
wimre: {dstdrive: "$($Paths.drive)"}
}
}
You also had a typo in either your template or your printout (I see that you used wimos in your "printout" in powershell and "winos" in your template. I modified the code and the following should work for you (given the above test.json):
$JSONConfig="c:\tmp\test.json"
function Get-ParsedJsonTemplate(){
return ($ExecutionContext.InvokeCommand.ExpandString((Get-Content $JSONConfig -Raw))) | ConvertFrom-Json
}
$pathJSON = Get-ParsedJsonTemplate;
$Paths=$pathJSON.Paths
$DefaultsJSON=Get-ParsedJsonTemplate;
$Defaults=$DefaultsJSON.Defaults
$JSON = Get-ParsedJsonTemplate;
$JSON.WIMS
write-host ("JSON.WIMS.wimre.dstdrive =" + $JSON.WIMS.wimre.dstdrive)
write-host ("JSON.WIMS.wimos.dstdrive =" + $JSON.WIMS.winos.dstdrive)
The reason your script was failing was due to the fact that $Defaults.wimos was not the string { dstdrive: "W:" } it was instead a PSCustomObject which would be interpolated to a the value #{drive=W:}. To obtain the correct behavior, you need to convert the $Defaults.wimos value back to a json string.
$Defaults = $DefaultsJSON.Defaults
$Defaults.wimos = $Defaults.wimos | ConvertTo-Json -Compress