6

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

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
Eiver
  • 2,594
  • 2
  • 22
  • 36
  • "*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 Aug 01 '16 at 18:42

10 Answers10

13

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.

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • Well its too bad, but apparently sometimes the correct answer is "No". – Eiver Aug 04 '16 at 10:40
  • 1
    @Eiver However unfortunate, yes :) – Mathias R. Jessen Aug 04 '16 at 10:42
  • This answer is incorrect. I was interested in developing functions that don't return the variable, or if wanted, use -passthru to return the modified object. This can be done by reference, but then you always have to code to make sure that the object being passed by reference is exactly as you anticipated. – Desthro Apr 24 '19 at 15:12
  • @Desthro I'm not sure I follow - how does this make my answer "incorrect" wrt. the question asked? (feel free to post an answer) :) – Mathias R. Jessen Apr 24 '19 at 15:43
8

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...

Martin Brandl
  • 56,134
  • 13
  • 133
  • 172
  • 2
    `Get-Variable | ? { [string]$args[0] -ceq $_.Value } | select -Expand Name` – Ansgar Wiechers Aug 01 '16 at 11:07
  • 1
    @AnsgarWiechers Nice idea! But would only work if there is no other variable assigned with the same value. – Martin Brandl Aug 01 '16 at 11:11
  • 2
    True, otherwise it'll return multiple results. But it's the only way I can see to get the name for a variable without knowing the name beforehand. `$args[0]` doesn't work as I had expected, though. Need a parameter or another variable there (and enumerate the parent scope, to avoid false positives from the function itself): `function MyFunc { Param($v); Get-Variable -Scope 1 | ? { $v -ceq $_.Value } | select -Expand Value }`. – Ansgar Wiechers Aug 01 '16 at 11:35
  • Your code does not make any sense: Of course, the idea is to use reflection the get the Variable Name - and not to manually write the Name again in the Code as you do. – Tom Nov 19 '19 at 16:40
5
$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.

peterh
  • 11,875
  • 18
  • 85
  • 108
gbiloux
  • 69
  • 1
  • 4
  • 1
    This should be the accepted answer for the first part of the question. – intrepidis Apr 20 '18 at 22:31
  • Solved my issue. Also realized that a diff btw single/double quoted strings is that single-quoted strings do not do variable expansion, so you could also do: Write-Host 'The variable name is $myVariable'. – galaxis Nov 09 '18 at 16:21
  • 2
    Of course, the idea is to detect the Variable Name - and not to manually write the Name again in the Code as you do. – Tom Nov 19 '19 at 16:37
1

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
Keith Langmead
  • 785
  • 1
  • 5
  • 16
1

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

Joma
  • 3,520
  • 1
  • 29
  • 32
0

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
TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87
0

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.

Ben Power
  • 1,786
  • 5
  • 27
  • 35
  • 1
    You understood it correctly. This will work for part 1 of the question. Thank you. It won't work for part 2 though, as explained in the accepted answer. – Eiver Sep 30 '19 at 08:54
  • Yeah, I'm not sure pt. 2 would be possible without something like reflection... which isn't a thing in PS – Ben Power Sep 30 '19 at 22:59
  • Your code does not make any sense: Of course, the idea is to use reflection the get the Variable Name - and not to manually write the Name again in the Code as you do. – Tom Nov 19 '19 at 16:40
  • @Tom It addresses the first part of the question. See Elver's comment – Ben Power Nov 20 '19 at 06:09
0

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
}
-1
$myVariable = "My Value"
$varname=[STRING]'$myVariable' -REPLACE ('\$')
Write-Host "The variable name is $varname"
Slava.K
  • 3,073
  • 3
  • 17
  • 28
Mikel V.
  • 351
  • 2
  • 8
-1

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
    ""
}
Zelda64
  • 97
  • 1
  • 3
  • Your code does not make any sense: Of course, the idea is to use reflection the get the Variable Name - and not to manually write the Name again in the Code as you do. – Tom Nov 19 '19 at 16:40