为什么在.ps1与.psm1文件中$ _的行为有所不同?

时间:2015-02-23 01:58:42

标签: powershell module pipeline

假设您在map_ps中定义map.ps1

function map_ps{
    [CmdletBinding()]
    param([parameter(ValueFromPipeline=$true)]$InputObject,$sb,$ArgumentList)
    process{&$sb $ArgumentList}
}

假设您还在名为map_psm的{​​{3}}模块中使用相同的实现定义了另一个函数map.psm1

function map_psm{
    [CmdletBinding()]
    param([parameter(ValueFromPipeline=$true)]$InputObject,$sb,$ArgumentList)
    process{&$sb $ArgumentList}
}

使用相同参数调用每个函数 会产生相同的结果:

PS C:\> 1 | map_ps  -sb {"DollarBar:$_, Arg:$($args[0])"} -ArgumentList 2
DollarBar:1, Arg:2
PS C:\> 1 | map_psm -sb {"DollarBar:$_, Arg:$($args[0])"} -ArgumentList 2
DollarBar:, Arg:2

$_中的函数实现时,为什么.psm1为空,但当函数在.ps1中实现时,它是不是?

2 个答案:

答案 0 :(得分:5)

除非在全局范围内声明变量,否则functions / ScriptBlocks无法看到模块中声明的变量与其自己的模块不同。作为解决方法,您可以通过[scriptblock]::Create创建ScriptBlocks,它创建的ScriptBlocks不受任何特定模块的限制:

function FunctionWithoutModule{
    [CmdletBinding()]
    param([parameter(ValueFromPipeline=$true)]$InputObject,$sb,$ArgumentList)
    process{
        $SomeVariable='SomeValue'
        &$sb $ArgumentList
    }
}
$Module=New-Module -ScriptBlock {
    function FunctionWithModule{
        [CmdletBinding()]
        param([parameter(ValueFromPipeline=$true)]$InputObject,$sb,$ArgumentList)
        process{
            $SomeVariable='SomeValue'
            &$sb $ArgumentList
        }
    }
}
$ScriptBlockWithoutModule={"DollarBar:$_, Arg:$($args[0]), SomeVariable:$SomeVariable"}
$ScriptBlockWithModule=$Module.NewBoundScriptBlock($ScriptBlockWithoutModule)
$ScriptBlockNotBoundToModule=[scriptblock]::Create($ScriptBlockWithoutModule)

1|FunctionWithoutModule -sb $ScriptBlockWithoutModule -ArgumentList 2
#DollarBar:1, Arg:2, SomeVariable:SomeValue
1|FunctionWithoutModule -sb $ScriptBlockWithModule -ArgumentList 2
#DollarBar:, Arg:2, SomeVariable:
1|FunctionWithoutModule -sb $ScriptBlockNotBoundToModule -ArgumentList 2
#DollarBar:1, Arg:2, SomeVariable:SomeValue
1|FunctionWithModule -sb $ScriptBlockWithoutModule -ArgumentList 2
#DollarBar:, Arg:2, SomeVariable:
1|FunctionWithModule -sb $ScriptBlockWithModule -ArgumentList 2
#DollarBar:1, Arg:2, SomeVariable:SomeValue
1|FunctionWithModule -sb $ScriptBlockNotBoundToModule -ArgumentList 2
#DollarBar:1, Arg:2, SomeVariable:SomeValue

答案 1 :(得分:2)

我认为这是Module scope和scriptblock的组合。在模块中更改了在scriptblock中使用局部变量的方式(这里在脚本块中使用$_来引用调用者范围中的变量)。

在脚本块上使用GetNewClosure()

function map_psm{
    [CmdletBinding()]
    param([parameter(ValueFromPipeline=$true)]$InputObject,$sb,$ArgumentList)
    process{& $sb.GetNewClosure() $ArgumentList}
}

那应该使用变量的当前值重新评估scriptblock。