Why does $_ behave differently when in a .ps1 versus .psm1 files?
module, pipeline, powershell
Solution
Unless variable declared in global scope, functions/ScriptBlocks can not see variables declared in module different from its own module. As workaround, you can create ScriptBlocks thru `[scriptblock]::Create`, which create ScriptBlocks not bounded to any particular module:
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
Problem
Suppose you define `map_ps` in `map.ps1`: ``` function map_ps{ [CmdletBinding()] param([parameter(ValueFromPipeline=$true)]$InputObject,$sb,$ArgumentList) process{&$sb $ArgumentList} } ``` Suppose you also define another function `map_psm` with identical implementation in a well-formed module called `map.psm1`: ``` function map_psm{ [CmdletBinding()] param([parameter(ValueFromPipeline=$true)]$InputObject,$sb,$ArgumentList) process{&$sb $ArgumentList} } ``` Calling each function with identical parameters does not yield the same result: ``` 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 ``` Why is `$_` empty when the function is implement in a `.psm1` but it isn't when the function is implemented in a `.ps1`?