powershellmultidimensional-arrayhashpass-by-reference

Short for creating an array of hashes in powershell malfunction?


I'm trying to initialize an array of hashes of a specific length in a short way. $array=@(@{"status"=1})*3 This does not work as I expect it to, when I change a value in the hash for one element in the array, all elements are updated

$a1=@(@{"status"=1},@{"status"=1},@{"status"=1})
$a2=@(@{"status"=1})*3
$a3=@(1)*3
$a1[1]["status"]=2
$a2[1]["status"]=2
$a3[1]=2
Write-Host "`nArray a1:"
$a1
Write-Host "`nArray a2:"
$a2
Write-Host "`nArray a3:"
$a3

I expect that only the second element in the array is affected by the update in all three scenarios. But this is what I get

   Array a1:

   Name                           Value                                                                                                                                    
   ----                           -----                                                                                                                                    
   status                         1                                                                                                                                        
   status                         2                                                                                                                                        
   status                         1                                                                                                                                        

   Array a2:
   status                         2                                                                                                                                        
   status                         2                                                                                                                                        
   status                         2                                                                                                                                        

   Array a3:
   1
   2
   1

Solution

  • .NET (and consequently PowerShell) distinguishes between value types and reference types - value types are data types whose values are copied on reference, whereas reference types are data types whose values are passed by reference.

    This means that "an array of hashtables" is not actually that - it's an array of references to hashtable(s).

    When you do: @($something) * 3, PowerShell creates and concatenates 3 copies of the @(...) array literal. If $something is of a reference type (like [hashtable] is), then the resulting array contains 3 copies of a reference to whatever $something references - which is exactly why changes to the hashtable referenced at 1 index of the array is reflected in the two other array references - because they're the same object.

    Use a loop (or the ForEach-Object cmdlet) to create 3 distinct hashtables instead of using @(...) * 3:

    $array = @(1..3|%{@{Status = $_}})