【问题标题】:Is there a concise way to pass a few existing variables to a Powershell function as parameters?有没有一种简洁的方法可以将一些现有变量作为参数传递给 Powershell 函数?
【发布时间】:2013-12-20 16:21:53
【问题描述】:

我似乎经常发现自己设置了一堆变量并且我想将它们传递给一个函数(例如,将参数传递给另一个函数而不进行修改)。目前我最终会做这样的事情:

Get-RelatedThing -CompanyTag $CompanyTag -ProjectTag $ProjectTag -EnvName $EnvName

这看起来很冗长,而且可读性不强。我可以使用位置参数,但这会牺牲清晰度和兼容性。预先创建一个数组并进行喷溅只会造成垂直混乱而不是水平混乱(除非在我可以执行 Get-RelatedThing @PSBoundParameters 之类的异常情况下,但这有缺陷)。

我真正想要的是能够做这样的事情:

Get-RelatedThing @(Get-Variable CompanyTag,ProjectTag,EnvName)

但是 Get-Variable 返回一个 Object[] 并且 splatting 运算符只能解析命名参数的哈希表(或位置参数的数组)。我stole一个函数解决了这个问题:

function Get-VariablesAsHashtable {

[CmdletBinding()]
param
(
    [Parameter(Position=0)]
    [string[]] $Name
)

$ObjectArray = Get-Variable -Name @($Name)

$Hashtable = @{}
$ObjectArray | Foreach { $Hashtable[$_.Name] = $_.Value }

return $Hashtable

}

“提前”运行时有效:

# works
$calculatedVars = (Get-VariablesAsHashtable ProjectTag,EnvName,ComponentTag);
(Get-RelatedThing @calculatedVars);

但不是在运行“内联”时:

# fails
(Get-RelatedThing @(Get-VariablesAsHashtable ProjectTag,EnvName,ComponentTag));

Get-InitialThing : Cannot process argument transformation on parameter 'ProjectTag'. Cannot convert value to type System.String.

我是否遗漏了一些可以解决这种方法的东西?或者有更好的方法吗?

【问题讨论】:

    标签: powershell


    【解决方案1】:

    实际上,您认为喷溅仅适用于哈希表是错误的。它也适用于数组,但它使用数组的每个元素作为调用命令的位置参数。如果您首先确定所有值都存在,则可以简单地分解数组:

    function Test-Binding {
    param (
        $Foo,
        $Bar
    )
        "Foo: $Foo"
        "Bar: $Bar"
    }
    
    $Foo = 'first value'
    $Bar = 'other value'
    
    $Splat = @(Get-Variable -ValueOnly Foo, Bar)
    
    Test-Binding @Splat
    

    您尝试过的内联语法失败的原因很简单:在这种情况下您没有喷溅。你在这一行中真正做了什么:

    (Get-RelatedThing @(Get-VariablesAsHashtable ProjectTag,EnvName,ComponentTag));
    

    ... 传递单个参数,您强制成为一个数组(在这种情况下 @() 代表),单个哈希表数组(您的函数生成的)。没有办法让你正在构建“临时”的哈希表。您需要先构建它,存储在变量 x 中,然后使用 @x 文字而不是通常的 $x 将此变量作为“splat”传递。

    我听说过填补这一空白的建议(使用类似 command @@{ foo = 'bar'} 的语法),但在此之前,您必须先构建哈希表/数组,然后使用变量名和 @ 前缀将其分解。

    【讨论】:

    • 谢谢,正是我所追求的。编辑我的问题以反映使用数组作为 splat 输入的可能性。
    【解决方案2】:

    看看这是否行不通:

    Get-RelatedThing @($(Get-Variable CompanyTag,ProjectTag,EnvName))
    

    实际上,您可以使用不同的功能进一步简化它。这显示了散布散列表的效果:

    $Params = @{
    CompanyTag = 'Company1'
    ProjectTag = 'Project1'
    EnvName    = 'Env1'
    }
    
    [Scriptblock]::Create("$(&{$args}@Params)")
    
    -EnvName: Env1 -CompanyTag: Company1 -ProjectTag: Project1
    

    修改您的原始功能以重现该功能:

    function Get-VariablesAsParameters {
    
    [CmdletBinding()]
    param
    (
        [Parameter(Position=0)]
        [string[]] $Name
    )
    
    $ObjectArray = Get-Variable -Name @($Name)
    [string]($ObjectArray | Foreach { '-{0}: {1}' -f $_.Name,$_.Value})
    
    }
    
    function Get-RelatedThing {$args}
    
    Get-RelatedThing $(Get-VariablesAsParameters CompanyTag,ProjectTag,EnvName)
    -CompanyTag: Company1 -ProjectTag: Project1 -EnvName: Env1
    

    【讨论】:

    • Get-RelatedThing @($(Get-Variable CompanyTag,ProjectTag,EnvName)) 对我来说与 Get-RelatedThing @(Get-VariablesAsHashtable ProjectTag,EnvName,ComponentTag) 没有任何不同...
    • Get-Variable 返回 PSVariable 的对象类型。该函数需要字符串。如果您只想使用 get-variable 传递变量的值,则必须使用 get-variable |选择 -expandproperty 值,或 (get-variable ).value
    猜你喜欢
    • 1970-01-01
    • 2021-08-21
    • 2022-12-10
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    • 2020-06-24
    • 2016-10-12
    • 1970-01-01
    相关资源
    最近更新 更多