如何在 powershell 中实现输出变量?

How do I implement output variables in powershell?

我意识到 "output variables" 可能是这里的错误术语,这就是为什么我的 google 搜索失败了。我猜它围绕显式设置变量范围展开,但我已经尝试阅读 about_Scopes 文档,它只是不适合我。

本质上,我想做的是在我自己的模块函数中实现 Invoke-RestMethod 中的 -SessionVariable 参数的等价物。换句话说,我需要一个字符串参数,它在调用者的范围内变成一个变量。

function MyTest
{
    param([string]$outvar)

    # caller scoped variable magic goes here
    set-variable -Name $outvar -value "hello world"

    # normal function output to pipeline here
    Write-Output "my return value"
}

# calling the function initially outputs "my return value"
MyTest -outvar myvar

# referencing the variable outputs "hello world"
$myvar

对于奖励积分,如果我正在包装一个具有自己的输出变量的现有函数并且我想有效地传递输出变量名称,事情会发生什么变化(如果有的话)?

function MyWrapper
{
    param([string]$SessionVariable)

    Invoke-RestMethod -Uri "http://myhost" -SessionVariable $SessionVariable

    # caller scoped variable magic goes here
    set-variable -Name $SessionVariable -value $SessionVariable
}

# calling the wrapper outputs the normal results from Invoke-RestMethod
MyWrapper -SessionVariable myvar

# calling the variable outputs the WebRequestSession object from the inner Invoke-RestMethod call
$myvar

P.S。如果重要的话,我正在努力使模块与 Powershell v3+ 兼容。

无需尝试自己实现,-OutVariableCommon Parameter

CmdletBinding attribute 添加到您的 param 块以免费获得这些:

function MyTest {
    [CmdletBinding()]
    param()

    return "hello world"
}

MyTest -OutVariable testvar

$testvar 现在保存字符串值 "hello world"

对于第二个示例,除了管道输出之外,您还需要在调用方范围内设置一个值,请将 -Scope 选项与 Set-Variable:

一起使用
function MyTest {
    [CmdletBinding()]
    param([string]$AnotherVariable)

    if([string]::IsNullOrWhiteSpace($AnotherVariable)){
        Set-Variable -Name $AnotherVariable -Value 'more data' -Scope 1
    }

    return "hello world"
}

MyTest -AnotherVariable myvar
调用方作用域中的

$myvar 现在包含字符串值 "more data"。传递给 Scope 参数的 1 值表示“向上一级”

@Mathias R. Jessen 提出了解决方案,当未在模块中定义时,该解决方案运行良好。但不是,如果你把它放在模块中。因此,我提供了另一种解决方案,将其放入模块后即可使用。

在高级功能(使用[CmdletBinding()] 属性的功能)中,您可以使用$PSCmdlet.SessionState 来引用调用者的SessionState。因此,您可以使用 $PSCmdlet.SessionState.PSVariable.Set('Name' ,'Value') 在调用方的 SessionState.

中设置变量

注意:如果未在模块中定义或从定义的同一模块调用,则此解决方案将不起作用。

New-Module {
    function MyTest1 {
        [CmdletBinding()]
        param([string]$outvar)
        $PSCmdlet.SessionState.PSVariable.Set($outvar, 'Some value')
    }
    function MyTest2 {
        [CmdletBinding()]
        param([string]$outvar)
        # -Scope 1 not work, because it executed from module SessionState,
        # and thus have separate hierarchy of scopes
        Set-Variable -Name $outvar -Value 'Some other value' -Scope 1
    }
    function MyTest3 {
        [CmdletBinding()]
        param([string]$outvar)
        # -Scope 2 will refer to global scope, not the caller scope,
        # so variable with same name in caller scope will hide global variable
        Set-Variable -Name $outvar -Value 'Some other value' -Scope 2
    }
} | Out-Null

& {
    $global:a = 'Global value'
    MyTest1 a
    $a
    $global:a
    ''
    MyTest2 a
    $a
    $global:a
    ''
    MyTest3 a
    $a
    $global:a
}