I use powershell to loop through multiple Json files obtained by the REST API. But the difficulty is that there are nodes with in them, and the name of a node is not fixed, we have no way to get it, wildcards seem to have no effect.
My test Json file Workflow_Info
like:
{
"id": "/subscriptions/fcxxxx7/resourceGroups/xxxxxx/providers/Microsoft.Web/sites/xxxx/workflows/Test_email",
"name": "xxxxxxxxx/Test_email",
"type": "Microsoft.Web/sites/workflows",
"kind": "Stateful",
"location": "East Asia",
"properties": {
"files": {
"Test_email/workflow.json": {
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Send_an_email_from_a_shared_mailbox_(V2)": {
"inputs": {
"host": {
"connection": {
"referenceName": "TheValueIwant"
}
},
"method": "post",
"path": "/v2/SharedMailbox/Mail"
},
"runAfter": {},
"type": "ApiConnection"
}
},
"contentVersion": "1.0.0.0",
"outputs": {}
},
"kind": "Stateful"
}
}
}
}
What I want to get is the value of the node referenceName.
But there are two difficulties:
-
The node
Test_emailworkflow.json
includes thein it, how to parse it?
-
The node
Send_an_email_from_a_shared_mailbox_(V2)
it is not a fixed value, it has different value in different json, I tried to use wildcard*
, but not work.
My test powershell scripts is:
$WorkflowJson = $Workflow_Info | ConvertTo-Json -depth 100
$WorkflowJsonNew = $Workflow_Info.properties.files."$($WorkflowName)/workflow.json".definition.'*'.host.connection.referenceName | ConvertTo-Json -depth 100
Write-Host "The workflow is:$WorkflowJsonNew"
4
Answers
For the first question, I have resolved it by add
""
for theTest_email/workflow.json
to get it:Now I could get the value.
But for the second question, I will open another question for some more details.
First: The JSON isn’t valid on multiple places.
=> Known problem with ""
This is a litle bit dirty. But it works in your case, because there are no further backslashes.
At least, a clean solution has been provided from the developer of the rest service. Currently the JSON is out of standard, see https://datatracker.ietf.org/doc/html/rfc8259 => Chapter "7. Strings"
=> Row 28 => "outputs": {}, => replace the "," at the end, because the list object has been finished.
=> Row 32 => }, => replace the "," at the end, because the list object has been finished.
To ensure a valid JSON, you should take a look here: https://jsonlint.com/
I’m using this since years.
Second: Your question about how to capture a unknown property name.
Please excuse my bad English. Computer languages are easier to learn as human languages. Regards from Bavaria.
The second question is a duplicate of:
(But as it has a bounty, it can be closed as such)
And can best resolved with the following function:
Usage
Finding node(s) with a specific name and value (-format):
Replacing the value of the found node(s):
Results
After your edits to the question that changed
to
/
, your first question no longer applies, and your own answer is no longer needed.and
/
, as already shown in the code in your question:$Workflow_Info.properties.files."$($WorkflowName)/workflow.json"
$Workflow_Info.properties.files."$WorkflowName/workflow.json"
, given that you don’t strictly need$(...)
inside expandable (double-quoted) string ("..."
) for stand-alone variable references such as$WorkflowName
– however, you do need$(...)
for expressions, such as$Workflows[0]
or$Workflow.Name
For verbatim names with unusual names, use verbatim (single-quoted) strings (
'...'
), e.g..([pscustomobject] @{ 'foobar' = 42 }).'foobar'
As for your second question:
You cannot use wildcards such as
*
to represent a property / properties of unknown names in a property path.However, you can combine the intrinsic
psobject
property with its.Properties
collection with member-access enumeration to achieve the same effect.A simplified example:
Note the
psobject.Properties.Value
part, which enumerates allproperty values and looks for a
.Parent
property on each.(Get-ChildItem $PROFILE).Name
,(Get-ChildItem $PROFILE).Length
, …, over all properties that aFileInfo
instance has.Situationally, there may be NO results (
$null
), ONE result, or an ARRAY of results.In the case at hand, only the
DirectoryInfo
instances stored in the.Directory
property has a.Parent
property, so that a single result – anotherDirectoryInfo
instance representing the parent directory of the directory in which the$PROFILE
file is located – is returned.By contrast, if you used
.Name
, you’d get three results, because the objects stored in the.PSDrive
,.PSProvider
, and.Directory
properties all have a.Name
property.Note that it is possible to use multiple
.psobject.Properties.Value
expressions in a single property path, one for each level of the object-graph hierarchy where the property name(s) are unknown.However, you always need to know at what level of the hierarchy the target value is to be found and provide the appropriate number of path components.
If not known, you need a solution that walks an entire object graph (hierarchy of nested objects) to look for properties of interest, as shown in iRon’s answer.
Applied to your case (this is a self-contained example that can be run as-is):