powershellpsobject

I want the string name of any Powershell variable


I would like to pass the string name of any Powershell variable to any function requiring a simple -Name parameter string e.g. $anyvar1 as a usable string with value 'anyvar1'. A function will use that variable's name literal var1 in this type of statement, which removes $var1:

      param (
            [string] $varName
            )
  try
    {
      Remove-Variable -Name $varName
    }
  catch{
  # trap any message if the variable doesn't exist
    }
  } 

I need this to be dynamic so if I pass any old variable to a function like this trivial example e.g.

     RemoveVar $anyvar1

it will just get the name, not like this where a string literal is used. T

     RemoveVar -Name '$anyvar1'

The second approach works, if the $ is stripped off the name literal and so on, but has be constructed.

So any function needing a simple -Name string parameter needs to get that name from the variable $anyvar1 object itself.

Get-Variable requires a simple name to get a variable as an object and thereby access any of its properties, including Name, but the chicken and egg situation occurs.

So a one-liner to get the object name property from any variable is needed. If it is of a particular scope, need to get the scope as well

So,

$Global:anyvar1="SOMEVALUE"
...
...
# all done with $Global:anyvar1
# figure out its name
$varName = Get-VarName -inputObject $Global:anyvar1   ??????

Remove-Variable -Name $varName -Scope Global
 # $varName would contain the literal Global:anyvar1.

the function Get-VarName does not exist AFAICT - but there must be a way to

Obviously any locally declared variables, or script level, go out of scope and so on, but $Global variables and others of that sort may need to be explicitly removed.

In C#, I would probably have used nameof(anyvar1) to do this, so something simple like that?

Any help is appreciated. It is probably blindingly obvious but I am not getting it.


Solution

  • Santiago has already provided helpful pointers in the comments; let me elaborate:


    Windows PowerShell solution, using an ArgumentCompleter attribute for tab-completion in combination with a ValidateScript for argument validation:

    function Invoke-Foo {
      param(
        [Parameter(Mandatory)]
        [ArgumentCompleter({ 
          param($command, $parameter, $wordToComplete)
          @((Get-Variable).Name) -like "$wordToComplete*" 
        })]
        [ValidateScript({
          if ($_ -notin (Get-Variable).Name) { throw "'$_' is not the name of an existing variable." }
          $true
        })]
        [string] $VarName
      )
    
      # Sample output.
      [pscustomobject] @{
        VarName = $VarName
        # Get the variable's value; note the indirection: the target
        # variable name is specified via the value of *another* variable,
        # $VarName
        VarValue = Get-Variable -ErrorAction Ignore $VarName -ValueOnly
      }
    
    }
    

    PowerShell (Core) 7+ solution, via a custom class implementing IValidateSetValuesGenerator, in combination with the ValidateSet attribute, which combines tab-completion with argument validation:

    class ExistingVariableNames : System.Management.Automation.IValidateSetValuesGenerator {
      [string[]] GetValidValues() { return (Get-Variable).Name }
    }
    
    function Invoke-Foo {
      param(
        [Parameter(Mandatory)]
        [ValidateSet([ExistingVariableNames])]
        [string] $VarName
      )
    
      # Sample output.
      [pscustomobject] @{
        VarName = $VarName
        VarValue = Get-Variable -ErrorAction Ignore $VarName -ValueOnly
      }
    
    }
    

    Note: