Not sure what I am doing wrong, but when copying a PSCustomObject in Powershell to an array element, this is copied by reference. See this:
$body = [PSCustomObject]@{
albumId = $album_id;
newMediaItems = [PSCustomObject]@()
}
$mediaItem = [PSCustomObject]@{
description = "";
simpleMediaItem = [PSCustomObject]@{
fileName = "";
uploadToken = "";
}
}
$mediaItem.description = "Friend of Mickey Mouse"
$mediaItem.simpleMediaItem.fileName = "Goofy.txt"
$mediaItem.simpleMediaItem.uploadToken = "1111"
$body.newMediaItems = $mediaItem.PsObject.Copy()
$mediaItem.description = "Friend of Rocker Duck"
$mediaItem.simpleMediaItem.fileName = "Donald Duck.txt"
$mediaItem.simpleMediaItem.uploadToken = "2222"
$body.newMediaItems = $mediaItem.PsObject.Copy()
$body | ConvertTo-Json -depth 4
Output:
{
"albumId": null,
"newMediaItems": [
{
"description": "Friend of Mickey Mouse",
"simpleMediaItem": {
"fileName": "Donald Duck.txt",
"uploadToken": "2222"
}
},
{
"description": "Friend of Rocker Duck",
"simpleMediaItem": {
"fileName": "Donald Duck.txt",
"uploadToken": "2222"
}
}
]
}
CodePudding user response:
.psobject.Copy()
performs shallow (member-wise) cloning of [pscustomobject]
instances.
Since your simpleMediaItem
property contains a reference to a .NET reference type (which happens to be another [pscustomobject]
instance), it is the reference that is copied, so that both the original [pscustomobject]
and the clone obtained via .psobject.Copy()
reference the very same object.
For deep (recursive) cloning (for which there is no universal solution), you'd have to create a custom implementation.
You can avoid the problem altogether using a custom class
definition:
class MediaItem {
[string] $description
[pscustomobject] $simpleMediaItem = [pscustomobject] @{
fileName = ""
uploadToken = ""
}
}
Now you can simply use [MediaItem]::new()
every time you want a new, independent instance.
To put it all together:
class MediaItem {
[string] $description
[pscustomobject] $simpleMediaItem = [pscustomobject] @{
fileName = ""
uploadToken = ""
}
}
$body = [PSCustomObject]@{
albumId = $album_id;
newMediaItems = @()
}
# Create a new instance.
$mediaItem = [MediaItem]::new()
$mediaItem.description = "Friend of Mickey Mouse"
$mediaItem.simpleMediaItem.fileName = "Goofy.txt"
$mediaItem.simpleMediaItem.uploadToken = "1111"
$body.newMediaItems = $mediaItem
# Create a new instance.
$mediaItem = [MediaItem]::new()
$mediaItem.description = "Friend of Rocker Duck"
$mediaItem.simpleMediaItem.fileName = "Donald Duck.txt"
$mediaItem.simpleMediaItem.uploadToken = "2222"
$body.newMediaItems = $mediaItem
$body | ConvertTo-Json -Depth 4
CodePudding user response:
What you're seeing is expected, you're only copying the base object. I would also recommend you doing this with function or a class, it would be much easier and no copying needed.
$body = [PSCustomObject]@{
albumId = $album_id;
newMediaItems = [PSCustomObject]@()
}
$mediaItem = [PSCustomObject]@{
description = "";
simpleMediaItem = [PSCustomObject]@{
fileName = "";
uploadToken = "";
}
}
$mediaItem.description = "Friend of Mickey Mouse"
$mediaItem.simpleMediaItem.fileName = "Goofy.txt"
$mediaItem.simpleMediaItem.uploadToken = "1111"
$body.newMediaItems = $mediaItem
$base = $mediaItem.PsObject.Copy()
$child = $mediaItem.simpleMediaItem.PSObject.Copy()
$base.description = "Friend of Rocker Duck"
$child.fileName = "Donald Duck.txt"
$child.uploadToken = "2222"
$base.simpleMediaItem = $child
$body.newMediaItems = $base