I'm having trouble with adding hashtables to a multidimensional array. I coded the following:
$Data = @{BIBs = @(
@{$BIB = @{BIBName=$BIBName},
@{Standort = $Standort},
@{Bücher = @(
@{BuchName = $BuchName;
Autor = $Autor
})
}}
)}
This code is functioning and creates an output, which I store in a JSON:
{
"BIBs": [
{
"BIB1": [
{
"BIBName": "123"
},
{
"Standort": "123"
},
{
"Bücher": [
{
"Autor": "123",
"BuchName": "123"
}
]
}
]
},
{
"BIB2": [
{
"BIBname": "345"
},
{
"Standort": "345"
},
{
"Bücher": [
{
"Autor": "345",
"Buchname": "345"
}
]
}
]
}
]
}
I have extra code which adds another hashtable to array "BIBs" as you can see.
$jsonfile = "C:\Skripte\bibV2-1000.json"
$Data = Get-Content $jsonfile | ConvertFrom-Json
$Data.BIBs += New-Object -TypeName PSObject -Property @{
$BIB = @{BIBname=$BIBName}, @{Standort=$Standort},
@{Bücher = @(@{Buchname=$BuchName;Autor=$Autor})}
}
When the output is like above, I'm not able to add another hashtable to "Bücher". I checked the type of "Bücher" with
$data.BIBs.BIB1.Bücher.GetType()
and it's actually an array:
IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Object[] System.Array
I tried
$Data.BIBs.BIB1.Bücher += @{Person="Max";Alter="35"}
to add a new hashtable, like I did with "BIB2", but I am getting the error:
The property 'Bücher' cannot be found on this object. Verify that the property exists and can be set. At line:5 char:1 + $data.BIBs.BIB1.Bücher += @{Motor="asdf";pers="345"} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : PropertyAssignmentException
Do you know how I add @{Person="Max";Alter="35"}
to "Bücher"?
tl;dr
Setting a key / property value via member-access enumeration is not supported (see below).
Instead, you must obtain the specific object whose
.Bücher
property you want to modify explicitly:Note: This assumes that:
$Data.BIBs.BIB1
has a.Bücher
property (key)?
(Where-Object
); like member-access enumeration, this simplifiedWhere-Object
syntax -? Bücher
instead of? { $_.Bücher }
- is a PSv3+ feature, called simplified syntax.Mathias R. Jessen has provided the crucial pointer in comments on the question:
PowerShell has an intentional asymmetry with respect to dot notation across collection-valued properties for getting values vs. setting values.
On getting, PSv3+ applies member-access enumeration, which, in a nutshell, allows you to access a property on a collection and implicitly get that property's value from each element IN that collection, with the results getting collected in an array.
On setting, member-access enumeration is not applied; the rationale is that the risk of unintentional modification of data is too high - see GitHub issue #5271 and in particular this comment by a core member of the PS team.
The unfortunate aspect is that the current error message doesn't tell you that.
It stems from the fact that when attempting to set a property at the collection level, the property is looked for only directly on the collection (instead of on its elements), where it (usually) doesn't exist.
Let's take a look at a simplified example:
On getting, everything works fine:
Even though
$data.a
is an[object[]]
array, an object (hashtable) with property.b3
was found among its elements, and that object's.b3
value is output.This is member-access enumeration in action (although the more typical uses is case for the property to exist on all elements of the array and for the individual values to be collected in an
[object[]]
array).On setting, PowerShell forgoes member-access enumeration and therefore unsuccessfully looks for a
.b3
property only directly on the[object[]]
instance that is$data.a
and, of course, arrays have no.b3
property: