1
votes

I have a function that returns the value of a global variable. When I assign this result to a local variable, and changing the local value the another variable is changing too.

Example:

function setGlobal
{
    $temp = @{}

    $temp.id = 50;

    $Global:global1 = $temp;

    return $Global:global1;
}

then I call this function, and set the result value:

$result = setGlobal
$result.id = 80

now both variables has the same value.

$Global:global1 # id = 60
$result # id = 60

How can I prevent this from happening? And why does changing the local value will affect the global copy?

2
The local changed the global because you actually have two things, a variable and a collection that variable is pointing at. you are not modifying the variable that holds collection, you are modifying the collection itself.. - Scott Chamberlain

2 Answers

3
votes

The reason is, of course, that you don't have two copies of the object. You have two references to the same object, a hashtable. The reference is copied, not the object. The object is like a house. The variables (global1 and result) are like pieces of paper. I write the address of the house on my piece of paper (global1) and then I copy the address onto your piece of paper (result). Then you go to the address you have and paint the door red. Now when I go to the address I have, and my house now has a red door.

Making a deep copy of an object is slightly easier than making a copy of a house. For an arbitrary object use PSObject.Copy():

function setGlobal
{
    $temp = @{}
    $temp.id = 50;
    $Global:global1 = $temp;
    return $Global:global1.PSObject.Copy();
}

In this case, this is exactly the same as Clone since PSObject.Copy uses Clone if it is available.

2
votes

This is happening because powershell is implicitly using references. So $Global:global1 and $result end up pointing to the same place when you make the assignment.

To get a copy, use the .Clone() method:

$result = $Global:global1.Clone()

Or instead of doing that on assignment, do it in the return of the function:

function setGlobal
{
    $temp = @{}

    $temp.id = 50;

    $Global:global1 = $temp;

    return $Global:global1.Clone();
}