从实际变量中获取 powershell 变量名

get powershell variable name from actual variable

我想弄清楚如何从对象本身获取 powershell 变量的名称。

我这样做是因为我正在更改通过引用传递给函数的对象,所以我不知道该对象是什么,我正在使用 Set-Variable cmdlet 来更改该变量只读。

# .__NEEDTOGETVARNAMEASSTRING is a placeholder because I don't know how to do that.

function Set-ToReadOnly{
  param([ref]$inputVar)
  $varName = $inputVar.__NEEDTOGETVARNAMEASSTRING
  Set-Variable -Name $varName -Option ReadOnly
}
$testVar = 'foo'
Set-ToReadOnly $testVar

我查看了很多类似的问题,但找不到任何具体的答案。我想完全在函数内部使用变量——我不想依赖于传递额外信息。

此外,虽然可能有 easier/better 设置只读的方法,但我一直想知道如何可靠地从变量中提取变量名,所以请重点解决这个问题,不是我在这个例子中的应用。

如前所述,您的要求(根据变量的值解析变量的身份)无法可靠地完成:

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.

对于引用类型,您可以做的只是遍历调用作用域中的所有变量并检查它们是否具有相同的值:

function Set-ReadOnlyVariable {
  param(
    [Parameter(Mandatory=$true)]
    [ValidateScript({ -not $_.GetType().IsValueType })]
    $value
  )

  foreach($variable in Get-Variable -Scope 1 |Where-Object {$_.Value -ne $null -and $_.Value.Equals($value)}){
    $variable.Options = $variable.Options -bor [System.Management.Automation.ScopedItemOptions]::ReadOnly
  }
}

但这会将调用者作用域中具有该值的每个变量设置为只读,而不仅仅是您引用的变量,我强烈建议您不要这样做 - 您很可能会做一些非常错误的事情如果你需要这样做

解释了为什么仅传递其 value.

就无法可靠地确定原始变量

解决您的问题的唯一 稳健 解决方案是 传递一个变量 object 而不是它的值作为参数:

function Set-ToReadOnly {
  param([psvariable] $inputVar) # note the parameter type
  $inputVar.Options += 'ReadOnly'
}

$testVar = 'foo'
Set-ToReadOnly (Get-Variable testVar) # pass the variable *object*

如果 您的函数定义在与调用代码相同的范围内 - 如果函数定义在一个(不同的)module - 你可以更简单地传递变量 name 并从父/祖先范围检索变量:

# Works ONLY when called from the SAME SCOPE / MODULE
function Set-ToReadOnly {
  param([string] $inputVarName)
  # Retrieve the variable object via Get-Variable.
  # This will implicitly look up the chain of ancestral scopes until
  # a variable by that name is found.
  $inputVar = Get-Variable $inputVarName
  $inputVar.Options += 'ReadOnly'
}

$testVar = 'foo'
Set-ToReadOnly testVar # pass the variable *name*