Eiver Eiver - 4 months ago 39
PowerShell Question

Is it possible to print variable names?

Is it possible to print variable names in PowerShell?

$myVariable = "My Value"
Write-Host "The variable name is ?????"


Expected output:


The variable name is myVariable


Question 2 (more tricky):
Is it possible to print variable name passed to a function in PowerShell?

Function MyFunc($myArg){
Write-Host "The variable name is ?????"
}

$myVariable = "My Value"
MyFunc $myVariable


Expected output:


The variable name is myVariable

Answer

No!

(at least not in a reliable fashion)

The simple reason being that contextual information about a variable being referenced as a parameter argument will have been stripped away by the time you can actually inspect the parameter value inside the function.

Long before the function is actually called, the parser will have evaluated the value of every single parameter argument, and (optionally) coerced the type of said value to whatever type is expected by the parameter it's bound to.

So the thing that is ultimately passed as an argument to the function is not the variable $myVariable, but the (potentially coerced) value of $myVariable.

see the about_Parsing help file (Get-Help about_Parsing) for more on this topic


It's maybe also worth noting that there's no guarantee that a parameter argument is a variable and not a literal or another value expression:

PS C:\> MyFunc 'This is not even a variable'
PS C:\> MyFunc $('Neither','is','this' -join ' ')

You can get some information about (potentially) used variables, by looking at the calling context, retrieved through the Get-PSCallStack cmdlet:

function Get-ImmediateInvocationString
{
    param($myArg)

    # Grab second-to-last call
    return @(Get-PSCallStack)[-2].InvocationInfo.Line
}

Then use it like:

PS C:\> $myVariable = "someValue"
PS C:\> Get-ImmediateInvocationString -myArg $myVariable
Get-ImmediateInvocationString -myArg $myVariable

You could (ab)use this to infer the argument to -myArg, by say grabbing the last "variable-like" string in the invocation:

function Get-ImmediateInvocationString
{
    param($myArg)

    # Grab second-to-last call
    $Line = @(Get-PSCallStack)[-2].InvocationInfo.Line
    if($Line -match '\$(?<varName>[\w]+)\s*$'){ 
        Write-Host $Matches['varName'] 
    }
}

This may seem like it works great at the onset:

PS C:\> Get-ImmediateInvocationString -myArg $myVariable
myVariable

Until a user who doesn't care about your conformance expectations comes along:

PS C:\> Get-ImmediateInvocationString -myArg $myVariable; $lol = ""; Write-Host $lol
lol

So no, you can't do what you want without parsing the calling expression in the same fashion as the actual parser does.

Comments