Setting a global PowerShell variable from a function where the global variable name is a variable passed to the function

Powershell

Powershell Problem Overview


I need to set a global variable from a function and am not quite sure how to do it.

# Set variables
$global:var1
$global:var2
$global:var3

function foo ($a, $b, $c)
{
    # Add $a and $b and set the requested global variable to equal to it
    $c = $a + $b
}

Call the function:

foo 1 2 $global:var3

End result:

$global:var3 is set to 3

Or if I called the function like this:

foo 1 2 $global:var2

End result:

$global:var2 is set to 3

I hope this example makes sense. The third variable passed to the function is the name of the variable it is to set.

Powershell Solutions


Solution 1 - Powershell

You can use the Set-Variable cmdlet. Passing $global:var3 sends the value of $var3, which is not what you want. You want to send the name.

$global:var1 = $null

function foo ($a, $b, $varName)
{
   Set-Variable -Name $varName -Value ($a + $b) -Scope Global
}

foo 1 2 var1

This is not very good programming practice, though. Below would be much more straightforward, and less likely to introduce bugs later:

$global:var1 = $null

function ComputeNewValue ($a, $b)
{
   $a + $b
}

$global:var1 = ComputeNewValue 1 2

Solution 2 - Powershell

As simple as:

$A="1"
function changeA2 () { $global:A="0"}
changeA2
$A

Solution 3 - Powershell

I ran across this question while troubleshooting my own code.

So this does NOT work...

$myLogText = ""
function AddLog ($Message)
{
    $myLogText += ($Message)
}
AddLog ("Hello")
Write-Host $myLogText

This APPEARS to work, but only in the PowerShell ISE:

$myLogText = ""
function AddLog ($Message)
{
    $global:myLogText += ($Message)
}
AddLog ("Hello")
Write-Host $myLogText

This is actually what works in both ISE and command line:

$global:myLogText = ""
function AddLog ($Message)
{
    $global:myLogText += ($Message)
}
AddLog ("Hello")
Write-Host $global:myLogText

Solution 4 - Powershell

You'll have to pass your arguments as reference types.

#First create the variables (note you have to set them to something)
$global:var1 = $null
$global:var2 = $null
$global:var3 = $null

#The type of the reference argument should be of type [REF]
function foo ($a, $b, [REF]$c)
{
    # add $a and $b and set the requested global variable to equal to it
    # Note how you modify the value.
    $c.Value = $a + $b
}

#You can then call it like this:
foo 1 2 [REF]$global:var3

Solution 5 - Powershell

The first suggestion in latkin's answer seems good, although I would suggest the less long-winded way below.

PS c:\temp> $global:test="one"

PS c:\temp> $test
one

PS c:\temp> function changet() {$global:test="two"}

PS c:\temp> changet

PS c:\temp> $test
two

His second suggestion however about being bad programming practice, is fair enough in a simple computation like this one, but what if you want to return a more complicated output from your variable? For example, what if you wanted the function to return an array or an object? That's where, for me, PowerShell functions seem to fail woefully. Meaning you have no choice other than to pass it back from the function using a global variable. For example:

PS c:\temp> function changet([byte]$a,[byte]$b,[byte]$c) {$global:test=@(($a+$b),$c,($a+$c))}

PS c:\temp> changet 1 2 3

PS c:\temp> $test
3
3
4

PS C:\nb> $test[2]
4

I know this might feel like a bit of a digression, but I feel in order to answer the original question we need to establish whether global variables are bad programming practice and whether, in more complex functions, there is a better way. (If there is one I'd be interested to here it.)

Solution 6 - Powershell

@zdan. Good answer. I'd improve it like this...

I think that the closest you can come to a true return value in PowerShell is to use a local variable to pass the value and never to use return as it may be 'corrupted' by any manner of output situations

function CheckRestart([REF]$retval)
{
    # Some logic
    $retval.Value = $true
}
[bool]$restart = $false
CheckRestart( [REF]$restart)
if ( $restart )
{
    Restart-Computer -Force
}

The $restart variable is used either side of the call to the function CheckRestart making clear the scope of the variable. The return value can by convention be either the first or last parameter declared. I prefer last.

Solution 7 - Powershell

For me it worked:

function changeA2 () { $global:A="0"}
changeA2
$A

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRadagastView Question on Stackoverflow
Solution 1 - PowershelllatkinView Answer on Stackoverflow
Solution 2 - PowershellKirt CarsonView Answer on Stackoverflow
Solution 3 - Powershellda_jokkerView Answer on Stackoverflow
Solution 4 - PowershellzdanView Answer on Stackoverflow
Solution 5 - PowershellAutoMattTickView Answer on Stackoverflow
Solution 6 - PowershellRobGView Answer on Stackoverflow
Solution 7 - Powershellbjorn80View Answer on Stackoverflow