I cannot find any solution why my where-clause in my powershell do not give me the output I would expect.
I have a JSON File looks like this:
[
{
"name": "server1",
"tag": ["App", "Mid-Tier", "User"],
"domain": "domainname",
"alias": ["Alias3"],
"ip": null,
"tcp": 8080,
"active": false,
"apps": ["ARS", "Tomcat"],
"patch": null,
"hotfix": null
},
{
"name": "server2",
"tag": ["Reporting"],
"domain": "domainname",
"alias": ["Alias3"],
"ip": null,
"tcp": 8080,
"active": false,
"apps": ["ARS", "Tomcat"],
"patch": null,
"hotfix": null
},
{
"name": "server3",
"tag": ["DB"],
"domain": "domainname",
"alias": ["Alias1", "Alias2", "Alias3", "Alias4"],
"ip": null,
"tcp": 8080,
"active": true,
"apps": ["SQL"],
"patch": null,
"hotfix": null
},
{
"name": "server5",
"tag": ["Reporting"],
"domain": "domainname",
"alias": ["Alias1"],
"ip": null,
"tcp": 8080,
"active": false,
"apps": ["ARS", "Tomcat"],
"patch": null,
"hotfix": null
}
]
EDIT/UPDATE
Ok I have to give you more details what I am trying to accomplish/understand:
I have 3 Files:
- a JSON File with data like above
- a script storing all functions and variables
- a main script
This is how my function looks like:
function opl_GetHostList {
[CmdletBinding()]
param (
[parameter (
mandatory=$false,
HelpMessage = "Enter alias name.")]
[string[]]
$Aliasname,
[parameter (
mandatory=$false,
HelpMessage = "Enter tag name.")]
[string[]]
$Tagname,
[parameter (
mandatory=$false,
HelpMessage = "Enter app name.")]
[string[]]
$Appname,
[parameter (
mandatory=$false,
HelpMessage = "Enter Active State: Either false or true. Default = true")]
[bool]
$Active = $true,
[parameter (
mandatory=$false,
HelpMessage = "Choose selection Object.")]
[string[]]
$Select
)
$WhereArray = #()
# evaluate these with contains comparison
if ($Aliasname) {$WhereArray += '$Aliasname -contains $_.alias'}
#if ($Tagname) {$WhereArray += '$Tagname -contains $_.tag'}
#if ($Appname) {$WhereArray += '$Appname -contains $_.apps'}
# Build the where array into a string by joining each statement with -and
$WhereString = $WhereArray -Join " -and "
# Create the scriptblock with your final string
$WhereBlock = [scriptblock]::Create($WhereString)
$opl_Hostlist | Where-Object {($WhereBlock.invoke()) -and $Active -eq $_.active} | Select-Object $Select
}
so now comes the part I don't understand.
If I use following in the main.ps1:
$opl_Hostlist | Where-Object {$_.alias -contains "alias3"} | Select-Object name
OUTPUT:
name
----
server1
server2
server3
BUT, if I use it with my function:
opl_GetHostList -Aliasname alias3 -Select name
I get this OUTPUT:
name
----
server1
server2
So why do I not get the "server3" with my second method when I am calling the data with my function?
Very thankfull for any help.
According to the JSON you have posted, you will get ConvertFrom-Json : Invalid array passed in, extra trailing ','. (1018) error. This is because of the unwanted comma after the last item.
And I would suggest to use -in instead of -match operation as Alias property is a list. In your comparison, left operand is a single element and right operand is a list, hence you have to use -in, otherwise -contains.
if ($Aliasname) {
$Aliasname | ForEach-Object{ $WhereArray += "$_ -in `$_.alias"}
}
$WhereArray -Join '-or'
Related
I am trying to get the list of "enabled" features from featureset array from below JSON snippet with powershell.
output expected :
feature1, feature2, feature4
I tried this piece of code but I was only able to get to the specific index of the array, not all elements, also not able to put condition for "enable" = true :
$output = foreach( $feature in $jsn.abc.comp1.featureset[0].psobject.Properties ) {
[PSCustomObject]#{
featureName = $feature.Name
featureValue = $feature.Value
}
}
json:
{
"abc": {
"comp1": {
"id": "1308",
"featureset":[
{
"name": "feature1",
"enable" : true,
"ID": "0670FF495355878281174937"
},
{
"name": "feature2",
"enable" : true,
"ID": "0670FF495355878281174937"
},
{
"name": "feature3",
"enable" : false,
"ID": "0670FF495355878281174937"
},
{
"name": "feature4",
"enable" : true,
"ID": "0670FF495355878281174937"
}
]
}
}
}
Loop over the whole featureset array, use Where-Object to filter:
$output = $jsn.abc.comp1.featureset |Where-Object enable -eq $true |ForEach-Object {
$_.Name
}
I want to get specific value once key is matched from JSON array object
Input:
[
{
"Id": "19A7A3C4",
"displayName": "somename",
"tags": [
{
"context": "CONTEXTLESS",
"key": "apple",
"value": "10"
},
{
"context": "CONTEXTLESS",
"key": "orange",
"value": "20"
},
{
"context": "CONTEXTLESS",
"key": "grapes",
"value": "30"
}
]
},
{
"Id": "111111",
"displayName": "somename",
"tags": [
{
"context": "CONTEXTLESS",
"key": "cat",
"value": "10"
},
{
"context": "CONTEXTLESS",
"key": "cat",
"value": "20"
}
]
}
]
I want to get the value of tag where key matches to cat and value matches to 10, I am using below query but getting whole object
$content = Get-Content -Raw -Path "data.json" | ConvertFrom-Json
$content | Where-Object{ $_.tags.key -eq "cat" -and $_.tags.value -eq "10"}
Desired Output: 10
Mathias's answer already shows a clean way to solve the problem.
A similar approach is using the intrinsic method .Where{}:
$tagValues = $content.tags.Where{ $_.key -eq "cat" -and $_.value -eq "10" }.value
$content.tags employs member enumeration to collect all tags properties into an array. .Where{} filters array elements similar to Where-Object. Lastly .value uses member enumeration again to collect the filtered tag values into an array.
Intrinsic methods like .Where{} are supposed to be faster than pipeline commands because they don't involve the overhead of the pipeline machinery.
If you want to keep your original query, you have to deal with nested properties.
Use grouping operator () and dot notation to extract a given property:
$tagValues = ($content | Where-Object{ $_.tags.key -eq "cat" -and $_.tags.value -eq "10"}).tags.value
An alternative is Select-Object with parameter -ExpandProperty (alias -Expand), but it doesn't work as straightforward for nested properties (yet):
$tagValues = $content | Where-Object{ $_.tags.key -eq "cat" -and $_.tags.value -eq "10"} |
Select-Object -Expand tags | Select-Object -Expand value
A more straightforward alternative is ForEach-Object:
$tagValues = $content | Where-Object{ $_.tags.key -eq "cat" -and $_.tags.value -eq "10"} |
ForEach-Object { $_.tags.value }
Enumerate all tags, then use ForEach-Object to grab just the value property of any match:
$content.tags | Where-Object { $_.key -eq "cat" -and $_.value -eq "10"} |ForEach-Object -MemberName value
here is my json body .
{
"source": 2,
"revision": 3,
"description": null,
"triggers": [],
"releaseNameFormat": "Release-$(rev:r)",
"tags": [],
"pipelineProcess": {
"type": 1
},
"properties": {
"DefinitionCreationSource": {
"$type": "System.String",
"$value": "BuildSummary"
},
"System.EnvironmentRankLogicVersion": {
"$type": "System.String",
"$value": "2"
}
},
"id": 5,
"name": "CheckListAPI - CD",
"path": "\\Admin",
"projectReference": null,
"url": "",
"_links": {
"self": {
"href": ""
},
"web": {
"href": ""
}
}
}
I want to add some values inside the brackets at "triggers": [],
What I'm trying to get is:
"triggers":
[
{
"artifactAlias": "_DV_NJ_PIPE",
"triggerConditions": [],
"triggerType": 1
}
],
i tried -replace and replace() saving the json file to local system, but none of them are working, I even tried to edit the json file directly like this but failed.
$alias = $json.triggers
foreach ($artifact in $alias )
{
$artifact.artifactAlias = "_$DefName"
$artifact.triggerConditions = "{}"
$artifact.triggertype = "artifactSource"
}
Please help.
You can import the json file as PowerShell objects, manipulate the structure until it looks the way you want it to and export it back to json format:
$pipeline = Get-Content .\input.json | ConvertFrom-Json
$trigger = [ordered]#{
artifactAlias = "_DV_NJ_PIPE"
triggerConditions = #()
triggerType = 1
}
$pipeline.triggers += $trigger
$pipeline | ConvertTo-Json -Depth 5 | Out-File .\output.json
As it was pointed out in the comments, it is of course also possible to import the trigger definition from a json file instead of building it in a hash table.
I am trying to get the key value from object inside JSON array, please also suggest if I need to change my RuleId key structure, below is the output I want
rule = 1300
rulevalue = false
rule = 1304
rulevalue = true
JSON file
{
"Rule": [{
"MPName": "ManagementPackProject",
"Request": "Apply",
"Category": "Rule",
"RuleId": {
"1300": "false",
"1304": "true"
}
}]
}
PowerShell
$Content = Get-Content -Raw -Path "C:\temp\Rule.json" | ConvertFrom-Json -ErrorAction Stop
$Content = $Content.Rule | Where-Object { $_.Request -eq "Apply" }
foreach($item in $Content.RuleId)
{
rule = $item.key
rulevalue = $item.value
process...
}
Are you after something like this?
$JSON = #'
{
"Rule": [{
"MPName": "ManagementPackProject",
"Request": "Apply",
"Category": "Rule",
"RuleId": {
"1300": "false",
"1304": "true"
}
}]
}
'#
$Content = $JSON | ConvertFrom-Json
$Content = $Content.Rule | Where-Object Request -eq 'Apply'
$Output = foreach( $Rule in $Content.RuleId.psobject.Properties ) {
[PSCustomObject]#{
Rule = $Rule.Name
RuleValue = $Rule.Value
}
}
$Output | Format-List
Output:
Rule : 1300
RuleValue : false
Rule : 1304
RuleValue : true
Im starting to learn PowerShell and have been trying to create a foreach loop so that if one of the JSON items has a status other than STARTED, it runs a command using its name as a variable in the executable command. Here is what my json txt file looks like;
{
"UNIT": {
"name": "AB",
"address": "fadasdaer",
"status": "MIA"
},
"UNIT": {
"name": "CD",
"address": "fadasdahsfaaer",
"status": "STARTED"
},
"UNIT": {
"name": "EF",
"address": "9afahegt",
"status": "DEAD"
}
}
And what I am trying to do is read this from my json.txt and get it to run a foreach loop and execute a command where the name is incorporated in the command. I currently have something like this, but my PowerShell understand is limited and it doesnt work...
$JSON = json.txt
$check = $JSON | ConvertFrom-Json
$started=STARTED
foreach($unit in $check.unit){
if ($unit.status -notmatch $started) {
$name=$unit.name
executable.exe start $name
}
}
Any guidance would be greatly appreciated.
Your primary problem is that your JSON is malformed: it defines a single object and then defines its UNIT property multiple times.
You should define it as an array: note the enclosing top-level [...] and the absence of UNIT properties:
[
{
"name": "AB",
"address": "fadasdaer",
"status": "MIA"
},
{
"name": "CD",
"address": "fadasdahsfaaer",
"status": "STARTED"
},
{
"name": "EF",
"address": "9afahegt",
"status": "DEAD"
}
]
With both the JSON input and your other syntax problems corrected:
$JSON = 'json.txt'
$check = Get-Content -Raw $JSON | ConvertFrom-Json
$started = 'STARTED'
foreach ($unit in $check) {
if ($unit.status -notmatch $started) {
$name = $unit.name
executable.exe start $name
}
}
If you cannot fix the JSON at the source, you can transform it yourself before passing it to ConvertFrom-Json:
$check = (Get-Content -Raw $JSON) `
-replace '\A\{', '[' `
-replace '\}\Z', ']' `
-replace '"UNIT": ' | ConvertFrom-JSON