Assigning a PowerShell variable the same value as another PowerShell variable is pretty straight forward. You set the variable equal to the other variable name. However, copying PowerShell hashtables is not as straight forward. If you don’t catch the issue right away, it can cause problems for your script or function.

In this post, you will learn how to copy a PowerShell hashtable the right way and what happens if you don’t. I’ll also provide a way to verify if two PowerShell hashtables are pointing to the same object.

Copying is copying, right?

To set the stage, let’s cover some introductory concepts. If you have a PowerShell variable named $string1 and want to assign the same string to $string2, it would look like this:

$string1 = 'This is my string.'
$string2 = $string1
$string1
$string2

If you modify $string2, the expectation is that $string1 remains unchanged. Let’s test that out.

So far so good. Next, build a hashtable and make a copy of it to another variable, displaying both to the screen.

$person1 = @{
    Name = 'Jeff'
    Age = 36
    Profession = 'Cloud Wrangler'
}

$person2 = $person1
$person1
$person2

You now have two hashtables with the same content. For $person2, add another property to the hashtable to using the .Add() method. Once completed, display $person1 and $person2 again to the screen.

$person2.Add('State', 'Washington')
$person1
$person2

Wait a minute, why does $person1 now have the State property when you only added it to $person2? You only made the change to one hashtable but it is reflected in the other.

That’s because copying a hashtable isn’t really copying the hashtable.

Hashtables are Objects

Variables assigned to hashtables aren’t actually storing the value of the hashtable. Hashtables are objects, so variables are only referencing the object. When you created $person1 and $person2, both variables are pointing to the same hashtable, not separate ones. This is why changing one changes the other.

You can verify this with a bit of .NET code and the [System.Object]::ReferenceEquals() method. This method determines whether two objects are referencing the same instance.

Use this method to compare both the string and person variables created earlier. The string methods should return false while the person variables will return true.

[System.Object]::ReferenceEquals($string1, $string2)
[System.Object]::ReferenceEquals($person1, $person2)

I supposed this isn’t a great test for the string since it is not an object, but the test is certainly valid for the hashtable. So how do you properly copy a hashtable?

Copying Hashtables (For Real)

For a one-level hashtable like the above example, use the .Clone() method. This method creates a new hashtable object and assigns it to a variable. Let’s create $person3 by cloning $person1, then follow this up by adding a new property to $person3. Finally, display both persons on the screen.

$person3 = $person1.Clone()
$person3.Add('City', 'Seattle')
$person3
$person1

Person 3 now has a property that Person 1 does not have as it is an entirely new object and not pointing to the same object. You verify this by using the ReferenceEquals() method from earlier. Note that Person 1 and Person 2 are still referencing the same object, so this returns True.

To copy hashtables with nested levels of properties, check out Kevin Marquette’s Everything You Wanted to Know About Hashtables. He provides a custom function for copying hashtables that have nested properties in them.

Closing

If you didn’t know that copying hashtables doesn’t actually copy them, you might tear your hair out trying to figure out why changes to one change another (as did I). With this article, you now have the tools available to avoid this mistake and continue with your PowerShell script and function writing.

If you enjoyed this article, check out my other PowerShell posts.

Questions or comments? If so, leave a comment below or find me on Twitter or LinkedIn to discuss further.

Leave a Reply