Function - Return Variable Option

This topic contains 0 replies, has 1 voice, and was last updated by Profile photo of Forums Archives Forums Archives 5 years, 4 months ago.

  • Author
    Posts
  • #5992

    by poshsavant at 2013-01-02 06:34:34

    Is POSH / .NET able to return the 'option' of a set variable. In other words, once a variable has been created and defined as read-only / constant / etc, is it possible to determine its type later on in the code?

    Sample code

    function Get-Constant([string] $varName)
    {
    $constants = @{
    pageBreak = "-" * 120
    pageBreakHalf = "-" * 60
    }

    if ($constants.ContainsKey($varName))
    {
    Set-Variable returnVar -Option ReadOnly -Value $constants.$varName
    Get-Variable returnVar | select Name,Value,Options | ft –AutoSize | Out-Host
    $returnVar
    }
    else
    {
    throw "Constant [$varName] does not exist!"
    }
    }

    function Test-GetConstant()
    {
    $pageBreakHalf = Get-Constant "PageBreakHalf"

    Get-Variable pageBreakHalf | select Name,Value,Options | ft –AutoSize | Out-Host

    }

    Test-GetConstant

    Sample Result

    Name Value Options
    ---- ----- -------
    returnVar ------------------------------------------------------------ ReadOnly

    Name Value Options
    ---- ----- -------
    pageBreakHalf ------------------------------------------------------------ None

    Notice that the 'read only' property does not seem to be passed along between the functions. I would love to hear thoughts / opinions on this feature 🙂

    Thanks

    by DonJ at 2013-01-02 07:33:58

    (FYI, Out-Host is redundant... it's the default)

    Read-only variables are still subject to scope. You're creating the variable in Get-Constant, or at least setting it which amounts to the same thing in PowerShell. If your intent is to set the variable in the script scope, which would be accessible to anything in the script, use the -Scope parameter.

    by poshsavant at 2013-01-02 08:25:49

    Don, thanks for the assistance. I know the sample provided is basic, but its a part of a larger module.

    So setting the scope parameter to global or script on the set-variable cmdlet throws an error of

    Set-Variable : Cannot overwrite variable returnVar because it is read-only or constant.

    I assume, you didnt mean to add the scope property to the get-variables

    by DonJ at 2013-01-02 11:16:52

    Ugh, not global. Please, not global. You can't predict what else might be going on in the global scope. Unwise to trash someone else's house. Stick with your script scope.

    If you've created the variable in a higher scope and set it to read-only... then of course, you can't change it. It's read-only. You're not supposed to change it.

    What's the goal here? Maybe if you explained to me what you're trying to do, I could help you come up with a good way to do it...?

    by poshsavant at 2013-01-02 12:55:55

    So the basic gist is to have a module filled with constants variables. So if I was playing with the excel com, I could import my standardize module of constants of headers and footers. However, if there is an overlap in variables names, I would prefer that it throws an error that the imported constant was read only. Does this make sense? If not, I can work on getting another example.

    Creating a custom object with a RO property does sort of provide an end solution. However, I am more curious why the above does not work as expected. We are returning a specific variable by value from a function and attempting to figure out its option. I am obviously missing something about scope.

    function Get-Constant( [string] $varName)
    {
    $constants = @{
    pageBreak = "-" * 120
    pageBreakHalf = "-" * 60
    }

    if ($constants.ContainsKey($varName))
    {
    $returnVar = New-Object -TypeName PSObject
    $returnVar | Add-Member -MemberType NoteProperty -Name Name -Value $varName
    $returnVar | Add-Member -MemberType NoteProperty -Name Values -Value $constants.$varName
    $returnVar | Add-Member -MemberType ScriptProperty -Name Options -Value {"Constant"}
    $returnVar | Select Name,Values,Options | ft –AutoSize | Out-Host
    $returnVar
    }
    else
    {
    throw "Constant [$varName] does not exist!"
    }
    }

    function Test-GetConstant()
    {
    $pageBreakHalf = Get-Constant "PageBreakHalf"
    $pageBreakHalf | select Name,Values,Options | ft –AutoSize | Out-Host

    try{
    $pageBreakHalf.Options = "Add Something Here"
    }catch{
    $Error[0]
    }

    }

    Test-GetConstant

    by DonJ at 2013-01-02 13:19:49

    The right thing to do if you're concerned about name collision is to test for the existence of a variable before you create it. That, and namespace your variables (e.g., $ExxonXLConstants if you work for ExxonMobile).

    Let's walk through your code, because I think you might indeed be missing something about scope.

    First executable line of code calls Test-GetConstant. First thing it does is run Get-Constant.

    Get-Constant creates a new variable, $returnVar, in its own scope. And then gets that variable. You write $returnVar to the pipeline, which winds up back in $pageBreakHalf inside Test-GetConstant. Get-Constant then ends, and $returnVar is destroyed.

    An important note here is that PowerShell passes ByVal, not ByRef. When Get-Constant writes $returnVar, it isn't writing the variable object itself. It's writing the contents of $returnVar to the pipeline, which is a hashtable. That's what goes into $pageBreakHalf. $pageBreakHalf is an independent variable and doesn't inherit any of the attribute of the actual $returnVar variable object. You didn't return a variable, per se; you returned the *contents* of the variable, which is a very different thing.

    I think I see where you were confused, now. You expected $pageBreakHalf to share the attributes of $returnVar, to wit, being read-only. Not how it works. You can't, using any normal syntax, copy the variable *itself*. Although a variable is indeed an object and does indeed have its own attributes, PowerShell likes to pretend otherwise. It mainly deals with their *contents*.

    The $ is the key. That's a dereferencing operator. When you use Set-Variable, you don't use $ on the variable name, right? That's because Set-Variable operates on the variable itself. $ always means "the contents of the variable." So you might think, "aha, I'll write returnVar to the pipeline instead of $returnVar." No, you won't. PowerShell doesn't use variables that way. Try it and it'll go look for a command named returnVar and barf red guts on the screen when it doesn't find one.

    Remember, this is a scripting language, not a full programming language. It takes a good number of shortcuts and, frankly, hacks that differentiate it from a more formalized language.

    That help?

    by poshsavant at 2013-01-02 18:18:19

    Don

    These two paragraphs cleared up the murky waters nicely.

    [quote]I think I see where you were confused, now. You expected $pageBreakHalf to share the attributes of $returnVar, to wit, being read-only. Not how it works. You can't, using any normal syntax, copy the variable *itself*. Although a variable is indeed an object and does indeed have its own attributes, PowerShell likes to pretend otherwise. It mainly deals with their *contents*.

    The $ is the key. That's a dereferencing operator. When you use Set-Variable, you don't use $ on the variable name, right? That's because Set-Variable operates on the variable itself. $ always means "the contents of the variable." So you might think, "aha, I'll write returnVar to the pipeline instead of $returnVar." No, you won't. PowerShell doesn't use variables that way. Try it and it'll go look for a command named returnVar and barf red guts on the screen when it doesn't find one.[/quote]

    I didnt realize that variables were interpreted as 'different' objects nor that $ was a dereferencing operator. My thanks for your time this afternoon to explain this one out. It is appreciated.

    I'll have to re-work somethings on our end then.

You must be logged in to reply to this topic.