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

Rya*_*ger 3 powershell powershell-3.0

我意识到"输出变量"可能是错误的术语,这就是为什么我的谷歌搜索失败了.我猜它是围绕明确设置变量范围,但我已经尝试阅读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
Run Code Online (Sandbox Code Playgroud)

对于奖励积分,如果我正在包装具有自己的输出变量的现有函数并且我想有效地通过输出变量名称,那么事情如何改变(如果有的话)?

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
Run Code Online (Sandbox Code Playgroud)

PS如果重要,我试图保持模块与Powershell v3 +兼容.

Mat*_*sen 7

没有必要尝试自己实现,-OutVariable是一个公共参数.

向块添加CmdletBinding属性param免费获取这些属性:

function MyTest {
    [CmdletBinding()]
    param()

    return "hello world"
}

MyTest -OutVariable testvar
Run Code Online (Sandbox Code Playgroud)

$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
Run Code Online (Sandbox Code Playgroud)

$myvar在调用者范围内,现在包含字符串值"more data".1传递给Scope参数的值意味着"1级"


use*_*407 5

@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
}
Run Code Online (Sandbox Code Playgroud)