Trying to understand Variable and Colon

This topic contains 8 replies, has 5 voices, and was last updated by  Graham Beer 2 years ago.

  • Author
    Posts
  • #31026

    Graham Beer
    Participant

    Looking through the brilliant "PowerShell in Action" and came across a script in the book that i need some clarification on.

    Function New-counter ($increment=1)
    { $count=0;
        {
        $script:count += $increment
        $count
    }.GetNewClosure()
    }
    

    I'm trying to get my head round this part $script:count += $increment.

    The $script is a new variable but it seems to be attaching the $count variable...$script:count...
    then passed to a new variable from the function....$increment

    How is this working ?

  • #31027

    Curtis Smith
    Participant

    This is variable scoping. It changes the variable scope to script rather than it's normal local scope inside of a function. Another one you will see occasionally is $global:variable. This changes the scope of the variable to global. Check out about_Scopes for more info.

    https://technet.microsoft.com/en-us/library/hh847849.aspx

  • #31030

    Dave Wyatt
    Moderator

    This particular example is a bit tricker than that. It's demonstrating the ScriptBlock.GetNewClosure() behavior. Because you've called GetNewClosure(), the script: scope modifier for each of the script block returned by New-Counter is _not_ actually in your script's script: scope. Here's an example of what I mean:

    Function New-counter ($increment=1)
    { $count=0;
        {
        $script:count += $increment
        $count
    }.GetNewClosure()
    }
    
    $script:count = 14
    
    $ctr1 = New-counter -increment 1
    $ctr2 = New-counter -increment 3
    
    & $ctr1
    & $ctr1
    & $ctr2
    & $ctr2
    

    Notice that I set $script:count to 14 before calling New-Counter. However, the output from this command is:

    1
    2
    3
    6

    Each counter maintains its own increment and count, isolated from the other counters (and from the actual script itself.) This is a pretty advanced technique for most PowerShell scripters, and can easily become pretty confusing to keep track of what's going on.

  • #31031

    Curtis Smith
    Participant

    Nice explanation, thanks Dave.

  • #31035

    Graham Beer
    Participant

    Thank you Curtis and Dave.
    Your right, not easy to get your head round.

    Could you call the :variable static? So you want to use it as a base but keep the original variable as is?

  • #31038

    Curtis Smith
    Participant

    Graham, it sounds like you are talking about a constant or readonly variable. Check out the help on Set-Variable.

    Set-Variable test -option Constant -value 100
    Set-Variable test -option ReadOnly -value 100
    
  • #31040

    Graham Beer
    Participant

    Thanks Curtis, but in trying to get my head around the scopes, I'm not looking for s solution, just an understanding. I was trying in my simple terms to learn how scopes work.

  • #31042

    Peter Jurgens
    Participant

    Here's a good test to give you an idea of the differences between Global, Script and Local (read: only within a function)

    Create a new ps1 script with the following content:

    $Script:var = "I AM SCRIPT"
    
    function test {
        $var = "I AM FUNCTION"
        "Testing `$Global:var = $Global:var"
        "Testing `$script:var = $Script:var"
        "Testing `$var = $var"
    }
    
    test
    $var
    

    And save as something like C:\test.ps1. Then open a powershell console and run the following:

    $var = "I AM GLOBAL"
    &C:\test.ps1
    

    Your output should be:
    Testing $Global:var = I AM GLOBAL
    Testing $script:var = I AM SCRIPT
    Testing $var = I AM FUNCTION
    I AM SCRIPT

    This is a very simple example, but I think you should get the gist of it.

    A practical example: If for instance you wish to set $ErrorActionPreference within a script or function without modifying the $ErrorActionPreference of your console session. You can modify the value within any script or function, run that script or function in a console, and the value will ONLY be changed within the context of the script or function that has been executed.

    If you wish to change the $ErrorActionPreference of your console session by running a function or script, you can reference $Global:ErrorActionPreference in your script or function, then when that script or function is executed in your console session it will update the Global ErrorActionPreference for that console session.

    Extracted from about_scopes:

    – An item you include in a scope is visible in the scope in which it
    was created and in any child scope, unless you explicitly make it
    private. You can place variables, aliases, functions, or Windows
    PowerShell drives in one or more scopes.

    – An item that you created within a scope can be changed only in the
    scope in which it was created, unless you explicitly specify a
    different scope.

  • #31063

    Graham Beer
    Participant

    Thanks Peter, i shall have a play 🙂

You must be logged in to reply to this topic.