I have a strange case running something in Powershell 7 returns the expected result, but in Powershell 5 it doesn't unless you break op the line in multiple assignments
Does anybody have an idea what goes wrong?
$wrong = az role assignment list --all --query "[? contains(scope,'/subscriptions/')]" | ConvertFrom-JSON | Select-Object *, @{n='Key';e={$_.scope+"|"+$_.roleDefinitionName+"|"+$_.principalName}} | Select -expand Key
Write-Host Wrong
$wrong[0]
$right = az role assignment list --all --query "[? contains(scope,'/subscriptions/')]" | ConvertFrom-JSON
$right = $right | Select-Object *, @{n='Key';e={$_.scope+"|"+$_.roleDefinitionName+"|"+$_.principalName}}
$right = $right | Select -expand Key
Write-Host Right
$right[0]
$wrong and $right are both correct in PowerShell 7 (Azure Portal Cloud Shell), but $wrong is giving the incorrect result in PowerShell 5 (from a DevOps pipeline)...
Wrong
/subscriptions/***/resourceGroups/***/providers/Microsoft.ApiManagement/service/***
Right
/subscriptions/***/resourceGroups/***/providers/Microsoft.ApiManagement/service/***|Owner|
The whole string concatenation done in the Select-Object command for new property Key only works when splitting the commands to multiple lines.
I'm quite new to PowerShell and have a hard time figuring out all the quirks...
ConvertFrom-Json
in PowerShell 5 (and, iirc earlier versions of 7.x), defaults to request that the pipeline processor not enumerate array output - meaning that if you pass a JSON document with a list/array as the root object to ConvertFrom-JSON
, it'll output the whole array object as one thing:
PS ~> '[1,2,3,4,5]' |ConvertFrom-JSON |ForEach-Object {"We received 1 item: '$_'"}
We received 1 item: '1 2 3 4 5'
You can counter this behavior by either breaking up the pipeline into two immediately downstream from ConvertFrom-JSON
(as you've found yourself) - or you can pipe the output to a command that enumerates the array anyways (here using Write-Output
):
PS ~> '[1,2,3,4,5]' |ConvertFrom-JSON |Write-Output |ForEach-Object {"We received 1 item: '$_'"}
We received 1 item: '1'
We received 1 item: '2'
We received 1 item: '3'
We received 1 item: '4'
We received 1 item: '5'
I should note that the 7.4 version of ConvertFrom-JSON
also has the ability to override this behavior via the -NoEnumerate
switch parameter, so that you get the same behavior as in 5:
PS ~> '[1,2,3,4,5]' |ConvertFrom-JSON -NoEnumerate |ForEach-Object { "We received 1 item: '$_'"}
We received 1 item: '1 2 3 4 5'