I need to create a singleton complex array. Background: I am trying to automate Let's Encrypt DNS challenge with GoDaddy. But the question is just about PS objects.
Suppose I have the following JSON object, which is my target notation
[
{
"data": "string",
"port": 0,
"priority": 0,
"protocol": "string",
"service": "string",
"ttl": 0,
"weight": 0
}
]
I try to initialize the variable via Powershell as follows
$goDaddyDnsBody=#(
#{
"data"= $dnsChallenge;
"port"= 1;
"priority"= 0;
"ttl"= 600;
"weight"= 0
}
)
The above code is supposed to create an array containing only one item
But when I try to Write-Host ($goDaddyDnsBody |ConvertTo-Json) I get only the first element, not the whole array
{
"weight": 0,
"priority": 0,
"data": ".................",
"ttl": 600,
"port": 1
}
The question is obvious: how can I make sure, without necessarily using string manipulation, that the object created is an array?
Great work with the self answer!
I wanted to point out two things:
the -AsArray parameter to ConvertTo-Json was not always available. It's in the current supported versions of PowerShell that are cross-platform. However, it is not available in Windows PowerShell (versions 5.1 and earlier) which many are still using.
The original issue stems from using the pipeline with an array that contains a single object. Because the pipeline is "unrolling" the array and passing each object into the cmdlet, with a single object array the cmdlet only ever sees the single object. For more on that, see mklement0's excellent and detailed explanation in another answer.
You can instead produce an array by passing the array directly to the parameter:
ConvertTo-Json -InputObject #(#{a=1})
Result:
[
{
"a": 1
}
]
Also worth noting that with the newer -AsArray option you don't need the wrapping array at all, in either the direct parameter or pipeline invocations:
ConvertTo-Json -InputObject #{a=1} -AsArray
#{a=1}|ConvertTo-Json -AsArray
I found the solution myself.
The problem is in with the serialization, not with the initialization of the singleton array. I just needed to add the following -AsArray switch
Write-Host ($goDaddyDnsBody |ConvertTo-Json -AsArray)
Sharing for posterity
Related
I struggle with very basic powershell scripting.
I have an object "ids" (I cant tell exactly what type it is) that translates to json like this
[{"id": "3ccbfe7a-e381-ed11-81ad-000d3aba6139","RowKey": "204640","PartitionKey": "ppm"},
{"id": "7339255d-e381-ed11-81ad-000d3aba6139","RowKey": "205269","PartitionKey": "ppm"}]
I simply want to get the "ids" by "rowkey". e.g.
$ids["204640"] shall resolve to "3ccbfe7a-e381-ed11-81ad-000d3aba6139".
It is obvious that this should be very easy - but I fail ... My understanding is, that it is a list or array of objects with named properties. I assume some simple casting magic is necessary...
(my debugging skills are very limited because I am a Powershell newbie and I do the scripting in the azure portal, trying to write an Azure Function using a table binding. actually "ids" comes from that binding.)
It is unclear if your Json string has already been converted into objects or not, for that you can use ConvertFrom-Json. Then you can use Group-Object -AsHashtable grouping on RowKey property:
$string = '
[
{"id": "3ccbfe7a-e381-ed11-81ad-000d3aba6139","RowKey": "204640","PartitionKey": "ppm"},
{"id": "7339255d-e381-ed11-81ad-000d3aba6139","RowKey": "205269","PartitionKey": "ppm"}
]
'
$hash = (ConvertFrom-Json $string) | Group-Object RowKey -AsHashTable
$hash['205269'].id # => 7339255d-e381-ed11-81ad-000d3aba6139
I have a PSObject that looks like this:
IsGettable : True
Value : {#{friority=Medium;removedDate=;etc..}
What I want to do is extract the friority that are medium and get a count of them.
I've tried a couple of different things using select-object and get-member with no luck.
Thanks in advance!
Update:
So, as suggested I converted the object into a JSON object and wrote it to the file.
{
"data": [
{
"id": 487777,
"proVersion": null,
"proName": null,
"revision": 0,
"folderId": 4555,
"friority": "Medium"}],
"count": 567,
"responseCode": 200
}
To save space I have removed some of the values of the object.
I have since changed the suggested solution to below:
($projIssues | Where-Object { $_.data.friority -eq "Medium" })
Now, If I add .count I am receiving the count value of the object
567
First off, Thanks to Santiago and mklement0 for the help.
I ended up using this statement:
$issues = $projIssues.data.friority | WHERE { $_ -eq "Medium"}
then checking the count like so:
$issues.count
I have below JSON
{
"id": " https://xxx.vault.azure.net/secrets/xxx ",
"attributes": {
"enabled": true,
"nbf": 1632075242,
"created": 1632075247,
"updated": 1632075247,
"recoveryLevel": "Recoverable+Purgeable"
},
"tags": {}
}
The above JSON is the output of a web activity and I am using this output into a ForEach activity. The above output when goes to ForEach activity as input, all the values are coming with escape characters.
{
{"id":" https://xxx.vault.azure.net/secrets/xxx ","attributes":{"enabled":true,"nbf":1632075242,"created":1632075247,"updated":1632075247,"recoveryLevel":"Recoverable+Purgeable"},"tags":{}}
From this JSON, I am trying to get only xxx value from the id attribute. How can I do this in Dynamic expression.
Any help is much appreciated.
Thanks
Use the built-in functions lastIndexOf (to find the last occurence of backslash), length (to determine the length of a string), add (to add numbers), sub (to subtract numbers) and substring to do this. For example:
#substring(item().id,add(lastIndexOf(item().id,'/'),1),sub(length(item().id),add(lastIndexOf(item().id,'/'),1)))
I need to process files in the container using Azure Datafactory and keep a track of processed files in the next execution.
so I am keeping a table in DB which stores the processed file information,
In ADF I am getting the FileNames of the processed files and I want to check whether the current file has been processed or not.
I am Using Lookup activity: Get All Files Processed
to get the processed files from DB by using below query:
select FileName from meta.Processed_Files;
Then I am traversing over the directory, and getting File Details for current File in the directory by using Get Metadata Activity: "Get Detail of Current File in Iteration"
and in the If Condition activity, I am using following Expression:
#not(contains(activity('Get All Files Processed').output.value,activity('Get Detail of current file in iteration').output.itemName))
This is always returning True even if the file has been processed
How do we compare the FileName from the returned value
Output of activity('Get All Files Processed').output.value
{
"count": 37,
"value": [
{
"FileName": "20210804074153AlteryxRunStats.xlsx"
},
{
"FileName": "20210805074129AlteryxRunStats.xlsx"
},
{
"FileName": "20210806074152AlteryxRunStats.xlsx"
},
{
"FileName": "20210809074143AlteryxRunStats.xlsx"
},
{
"FileName": "20210809074316AlteryxRunStats.xlsx"
},
{
"FileName": "20210810074135AlteryxRunStats.xlsx"
},
{
"FileName": "20210811074306AlteryxRunStats.xlsx"
},
Output of activity('Get Detail of current file in iteration').output.itemName
"20210804074153AlteryxRunStats.xlsx"
I often pass this type of thing off to SQL in Azure Data Factory (ADF) too, especially if I've got one in the architecture. However bearing in mind that any hand-offs in ADF take time, it is possible to check if an item exists in an array using contains, eg a set of files returned from a Lookup.
Background
Ordinary arrays normally look like this: [1,2,3] or ["a","b","c"], but if you think about values that get returned in ADF, eg from Lookups, they they look more like this:
{
"count": 3,
"value": [
{
"Filename": "file1.txt"
},
{
"Filename": "file2.txt"
},
{
"Filename": "file3.txt"
}
],
"effectiveIntegrationRuntime": "AutoResolveIntegrationRuntime (North Europe)",
"billingReference": {
"activityType": "PipelineActivity",
"billableDuration": [
{
...
So what you've got is a complex piece of JSON representing an object (the return value of the Lookup activity plus some additional useful info about the execution), and the array we are interested in is within the value object. However it has additional curly brackets, ie it is itself an object.
Solution
So the thing to do is to pass to contains something that will look like your object which has the single attribute Filename. Use concat to create the string and json to make it authentic:
#contains(activity('Lookup').output.value, json(concat('{"Filename":"',pipeline().parameters.pFileToCheck,'"}')))
Here I'm using a parameter which holds the filename to check but this could also be a variable or output from another Lookup activity.
Sample output from Lookup:
The Set Variable expression using contains:
The result assigned to a variable of boolean type:
I tried something like this.
from SQL table, brought all the processed files as comma-separated values using select STRING_AGG(processedfile, ',') as files in lookup activity
Assign the comma separated value to an array variable (test) using split function
#split(activity('Lookup1').output.value[0]['files'],',')
meta data activity to get current files in directory
filter activity to filter the files in current directory against the processed files
items:
#activity('Get Metadata1').output.childitems
condition:
#not(contains(variables('test'),item().name))
I have a Get Metadata activity which get all child items under a blob container. There are both files and folders but i just need files. So in a filter activity which filter for only items of type = file. This is what I got from the filter activity:
Output
{
"ItemsCount": 4,
"FilteredItemsCount": 3,
"Value": [
{
"name": "BRAND MAPPING.csv",
"type": "File"
},
{
"name": "ChinaBIHRA.csv",
"type": "File"
},
{
"name": "ChinaBIHRA.csv_20201021121500",
"type": "File"
}
]
}
So there is an array of 3 objects being returned. Each object has a name and type properties. I want just the names to be fed to a store procedure activity as a parameter. I have used this expression to try to get a comma separated list as the parameter.
#join(activity('Filter1').output.Value.name, ',')
and got this error:
The expression 'join(activity('Filter1').output.Value.name, ',')' cannot be evaluated because property 'name' cannot be selected. Array elements can only be selected using an integer index.
So how can I achieve this?
You can create For Each activity after Filter activity. Within For Each activity, append file name.
Step:
1.create two variable.
2.Setting of For Each activity
3.Setting of Append Variable activity within For Each activity
4.Setting of Set variable
Use the below codeblock instead
#concat('''',join(json(replace(replace(replace(replace(string(
activity('Filter1').output.Value)
,',"type":"File"','')
,'"name":','')
,'{','')
,'}','')),''','''),'''')
This would forego the use of multiple activities, and you can use the existing framework that you have.