5
votes

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

10
"Is it possible to print variable names in PowerShell?" - sure is; check out the number of posts on StackOverflow where people ask: "Write-Host 'The variable name is $myVariable' - why is this only showing the name, not the value?" - TessellatingHeckler

10 Answers

13
votes

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.

6
votes

You could use the Get-Variable cmdlet to resolve the variable and then select the name but you still have to specify the name so its kind of useless:

(Get-Variable myVariable | select -ExpandProperty Name)

Output:

myVariable

I doubt its possible to print the name of the variable you are passing to a function...

5
votes
$myVariable = "My Value"
Write-Host "The variable name is **`**$myVariable"

Before editing my post just look the small " ` " signe before the "$" This is the thing that alloow printing variable name as it is.

1
votes

For question 2, depending on what you're trying to achieve the following may do what you need :

function showDebug
{
Param(

    [string]$debugVariable
)
    $debugValue = Get-Variable $debugVariable
    write-host "Variable `$$($debugValue.Name) = $($debugValue.Value)"
} 

$tempvariable = "This is some text"
showDebug "tempvariable"

In my case I just wanted a function to output some debug info (it'll check whether debugging is enabled and other stuff in the function itself later), and output the name of the variable and what's assigned to it.

If you pass the actual variable to the function it won't work, BUT if you pass the name of the variable as a string (eg "tempvariable" rather than $tempvariable), the Get-Variable cmdlet will successfully query it and return the Name and Value pair so they can both be referenced as required.

So using this the result returned is :

Variable $tempvariable = This is some text
0
votes

Is it possible to print variable names in PowerShell?

$myVariable = "My Value"

Write-Host "The variable name is ?????"

To achieve what?

PS C:\> $originalNames = (get-variable).Name + 'originalNames'
PS C:\> $myVariable = "~ My ~ Value"
PS C:\> write-Host "The variable name is: $((Get-Variable).Name |? {$_ -notin $originalNames})"
The variable name is: myVariable
0
votes

I might be misunderstanding this, but I've just done:

> $myVariable="something"
> (get-variable myVariable).Name
myVariable

I've got Powershell 5.1.17763.592 installed.

0
votes

Messy, but without writing the name of the variable back into the script as hard-coded. You only need to change line 6 of the below

Try {
    # Get a list of all set variables
    $AutomaticVariables = Get-Variable

    # Set your variable
    $TestVariable = 'Bloop'

    # Compare another list of all set variables to determine what has been set since
    $NewestVariable = Compare-Object (Get-Variable) $AutomaticVariables -Property Name -PassThru | Where -Property Name -ne "AutomaticVariables"

    # Defensive check to ensure exactly 1 entry is present
    if ($($NewestVariable | Measure-Object).Count -ne 1) {
        Write-Host "ERROR : Unable to determine most recently set variable"
        throw
    }

    # Display Result
    Write-Host "Newest variable $($NewestVariable.Name) has value    $($NewestVariable.Value)"
} Catch {
    Write-Host "ERROR : $($_.Exception.Message)"
    Exit 1
}
0
votes

Code

Based on accepted answer in this question. Is it possible to print variable names?

function Get-VariableName {
    Param(
        [Parameter()]    
        [System.Object]
        $Variable
    )
    $Line = @(Get-PSCallStack)[1].Position.Text
    if ($Line -match '(.*)(Get-VariableName)([ ]+)(-Variable[ ]+)*\$(?<varName>([\w]+:)*[\w]*)(.*)') { #https://regex101.com/r/Uc6asf/1
        return $Matches['varName'] 
    }
} 

$myVar = "HelloWorld"
Get-VariableName -Variable $myVar
Get-VariableName $myVar
Get-VariableName $env:PATH

Output

PS /home/x> Get-VariableName -Variable $myVar
myVar
PS /home/x> Get-VariableName $myVar
myVar
PS /home/x> Get-VariableName $env:PATH
env:PATH
PS /home/x>

Windows 10 - Powershell Core - Powershell 7.1 Windows

WSL - Ubuntu 20.04 - Powershell Core - Powershell 7.1 Ubuntu WSL

Ubuntu 20.04 - Powershell Core - Powershell 7.1 Ubuntu 20.04

-1
votes
$myVariable = "My Value"
$varname=[STRING]'$myVariable' -REPLACE ('\$')
Write-Host "The variable name is $varname"
-1
votes

Regarding question 1; the desired variable is not specified in the command

Write-Host "The variable name is ?????"

so it is impossible for the Write-Host command to know which variable you want the name of.

For example:

$1stVariable = "1st Value"
$2ndVariable = "2nd Value"

Write-Host "The variable name is ?????"

How would PowerShell know if you wanted the name of $1stVariable or $2ndVariable unless you specify which one. Therefore, if the variable name(s) are not directly specified, a separate variable that stores all the variable info must be specified, like my additional example.


Answer to Question 1

$myVariable = "My Value"

"The variable name is $((Get-Variable myVariable).Name)"    
"The variable value is $((Get-Variable myVariable).Value)"

Answer to Question 2

$AnotherVariable = "Another Value"

Function MyFunc ($myArg) {
   "The variable name is $($myArg.Name)"
   "The variable value is $($myArg.Value)"
}

MyFunc (Get-Variable AnotherVariable)

Additional Example

# No specific variable names are passed as arguments to the function "CustomFunc". 

$Var1 = "1st"
$Var2 = 2
$Var3 = "3rd"
$Var4 = 4

$AllVars = (Get-Variable Var1, Var2, Var3, Var4)

Function CustomFunc ($myArg) {
   "The variable name is $($myArg.Name)"
   "The variable value is $($myArg.Value)"
}

ForEach ($Var in $AllVars) {
    CustomFunc $Var
    ""
}