PowerShell function with parameterized script block

I want to create a PowerShell function that enumerates some data and runs a script block for all occurrences.

Now I have (this is not real code, but it illustrates my problem):

function Invoke-TenTimes { [CmdletBinding()] param ( [Parameter(Mandatory=$true, Position=0)] [ScriptBlock]$Action ) process { $digits = 0..10 $digits | % { $Action.Invoke($_); } } } 

I put this function in my module. However, I do not get any result when I call:

 Invoke-TenTimes { $_ } 

The output is empty (nothing is displayed).

If i call

 Invoke-TenTimes { $_ -eq $null } 

I get ten true . In fact, I see that $_ is null.

What is the correct way to populate $_ ?

What drives me crazy is that if I put this function and the call in the same ps1 file, it works (but I want to pass the script block on request):

 function Invoke-TenTimes { [CmdletBinding()] param ( [Parameter(Mandatory=$true, Position=0)] [ScriptBlock]$Action ) process { $digits = 0..10 $digits | % { $Action.Invoke($_); } } } Invoke-TenTimes { $_ } 
+7
source share
4 answers

this is a problem related to the transfer in a script block belonging to a different area than where it is running. If the one passed to scriptblock should not refer to variables from its context, you can simply clone the script block to make it reside in the area in which you use it. from

 $action = [scriptblock]::Create($action) 

The interesting thing is that it only worked first of all ACCIDENTS. he received $ _ from the parent area, where the script block belonged, which turned out to be inside you for an object object that was good.

however grab your original version and then run this

 "gotcha" | % { Invoke-TenTimes { $_ } } 

and you will see that you get getcha 10 times, because $ _ is not null in the area of ​​your callers, but it is something.

+2
source

Here we go:

 $scriptblock = {param($number) Write-Host "Current Number is $number"} function Invoke-TenTimes { [CmdletBinding()] param ( [Parameter(Mandatory=$true, Position=0)] [ScriptBlock]$Action ) $digits = 1..10 $digits | ForEach-Object{Invoke-Command -ScriptBlock $Action -Args $_} } 

Using:

 Invoke-TenTimes $scriptblock 
+5
source

The problem is known, and it is specific to modules. Perhaps this is even a mistake. Please take a look at this question: Strange behavior with scope and modules of the Scriptblock Powershell variable, any suggestions?

For your specific case, call your function as follows:

 Invoke-TenTimes { $args[0] } 

Therefore, it should work as expected.

+3
source

This is much simpler than everyone allows.

Consider that $ A and $ B are defined at the global level, and only level B is defined at the module level. Your script block is the third area. In it, you refer to $ A and get a global value. Similarly, if you refer to $ B, you get the module level value, since it overshadows the global instance.

PROBLEM: If you try to write either, a local instance is created.

Answer:

 ([ref]$A).value = 'Something malicious' 

Note that "([ref] $ {name})" is a reference object, so ".value" is required to reach the actual variable. So

 ([ref]$B).value.Length 

coincides with

 $B.Length 

In any case, you do not have direct control over the area. You get a copy from which you would read. Thus, the first example modifies the global $ A, and the second example refers to a module level instance of $ B.

0
source

All Articles