none
How can I call a functin in ForEach -Parallel ? RRS feed

  • Dotaz

  • Function Show($s) { $s }
    '1234','5678','asdf'| ForEach -Parallel { Show $_ }

    When running above, I got error below. what's wrong?

    Show : The term 'Show' is not recognized as the name of a cmdlet, function, script file, or operable program.
    Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:2
    +  Show $_
    +  ~~~~
    + CategoryInfo          : ObjectNotFound: (Show:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    neděle 20. října 2019 19:10

Odpovědi

  • I had time to update this machine to the latest preview. The Parallel works as expected and take a scriptblock as an argument:

    '1234','5678','asdf'|
    	ForEach-Object -Parallel {
    		function Show{
    			param($s)
    			$s
    		}
    		Show $_
    	}
    The code used uses a "PSTask" named runspace for the threads.


    \_(ツ)_/


    • Upravený jrvModerator úterý 22. října 2019 0:10
    • Označen jako odpověď Ian3 středa 23. října 2019 2:51
    úterý 22. října 2019 0:09
    Moderátor

Všechny reakce

  • Them function must be defined inside the scriptblock.

    Start learning how to use workflow by reading the documentation provided.  Also learn how scriptblocks that run in remote or external session need to be designed. This is all basic PowerShell 1010 which you need to know before trying to use PS 7.

    The error message is fundamental to all versions of PowerShell and tells you that the item complained about is out-of-scope or does not exisit in the current PS session.


    \_(ツ)_/

    neděle 20. října 2019 19:46
    Moderátor
  • If this is about powershell 7, there doesn't seem to be a way besides calling a script instead.  Scriptblock variables didn't work either.

    'param($s) $s' > Show.ps1  # utf8 no bom in ps 7
    echo 1234 5678 asdf | ForEach -Parallel { .\Show $_ }

    • Upravený JS2010 pondělí 21. října 2019 15:05
    pondělí 21. října 2019 3:38
  • The function must be included in the scriptblocks as always.

    '1234','5678','asdf'| 
    	ForEach -Parallel {
    		function Show($s){$s}
    		Show $_ 
    	}


    \_(ツ)_/

    pondělí 21. října 2019 3:51
    Moderátor
  • This is the same "ForEach-Object" but with an added functionality.

    https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/foreach-object?view=powershell-7


    \_(ツ)_/

    pondělí 21. října 2019 4:02
    Moderátor
  • Scriptblock example, showing that it doesn't work.

    Function Show($s) { $s }
    $a = $function:show  # scriptblock
    '1234','5678','asdf'| ForEach -Parallel { & $using:a $_ }

    ForEach : A ForEach-Object -Parallel using variable cannot be a script block. Passed-in script block variables are not supported with ForEach-Object -Parallel, and can result in undefined behavior.
    At line:1 char:23
    + '1234','5678','asdf'| ForEach -Parallel { & $using:a $_ }
    +                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidType: (Microsoft.PowerShel…orEachObjectCommand:ForEachObjectCommand) [ForEach-Object], PSArgumentException
    + FullyQualifiedErrorId : ParallelUsingVariableCannotBeScriptBlock,Microsoft.PowerShell.Commands.ForEachObjectCommand

    • Upravený JS2010 pondělí 21. října 2019 15:10
    pondělí 21. října 2019 14:03
  • Scriptblock example, showing that it doesn't work.

    Function Show($s) { $s }
    $a = $function:show  # scriptblock
    '1234','5678','asdf'| ForEach -Parallel { & $using:a $_ }

    ForEach : A ForEach-Object -Parallel using variable cannot be a script block. Passed-in script block variables are not supported with ForEach-Object -Parallel, and can result in undefined behavior.
    At line:1 char:23
    + '1234','5678','asdf'| ForEach -Parallel { & $using:a $_ }
    +                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidType: (Microsoft.PowerShel…orEachObjectCommand:ForEachObjectCommand) [ForEach-Object], PSArgumentException
    + FullyQualifiedErrorId : ParallelUsingVariableCannotBeScriptBlock,Microsoft.PowerShell.Commands.ForEachObjectCommand

    What does this have to do with the original question?


    \_(ツ)_/

    pondělí 21. října 2019 17:55
    Moderátor
  • It would be almost like running a pre-defined function in the foreach.
    pondělí 21. října 2019 18:04
  • A ForEach -Parallel executes the ScriptBlock in a new runspace for each iteration. That runspace is a new copy of PowerShell that cannot see the scope that the code is called from. Because of this we need to include all variables and functions in the scriptblocks.

    There is an alternate form used with ForEach that we can also use.  A ForEach has three useful parameters "Begin/Process/nd" that allow us to set up the pipeline.  (Remember that ForEach-Object only works in a pipeline.

    '1234','5678','asdf'| 
    	ForEach-Object -Begin {
    			function Show{
    				param($s)
    				$s
    			}
    			Write-Host 'Begin completed'
    		} -Process {
    			Show $_ 
    		} -End{
    			Write-Host 'End completed'
    		} -Parallel
    
    Run this with and without the "-Parallel" and it will work the same way but the "Parallel" version will use multiple runspaces.


    \_(ツ)_/

    pondělí 21. října 2019 18:32
    Moderátor
  • It gives me an error:


    ForEach-Object : Missing an argument for parameter 'Parallel'. Specify a parameter of type 'System.Management.Automation.ScriptBlock' and try again.

    • Upravený JS2010 pondělí 21. října 2019 18:52
    pondělí 21. října 2019 18:51
  • It gives me an error:


    ForEach-Object : Missing an argument for parameter 'Parallel'. Specify a parameter of type 'System.Management.Automation.ScriptBlock' and try again.

    You are not running the correct versions of Core and PS 7.

    ForEach-Object -Parallel also also experimental in the latest preview so it may not work correctly.  Move the Parallel to the start of the list to see if that helps although it shouldn't.

    In all cases you cannot access exter5nal variables or functions for any "Parallel" operations in runspaces, jobs or workflows.  That has always been true.

    I also checked the docs and begin/process/end are not supported when "Parallel" is used.   THis will likely be changed in a future release.  Runspaces support startup code and the end-invoke can be used to supply "End" functionality.  Maybe the guys writing this will revisit and provide more consistency.

    For issue with PS7 preview you must post in UserVoice or the PowerShell Core forums.

    For now just add the function to the ScriptBlock.


    \_(ツ)_/

    pondělí 21. října 2019 19:22
    Moderátor
  • I had time to update this machine to the latest preview. The Parallel works as expected and take a scriptblock as an argument:

    '1234','5678','asdf'|
    	ForEach-Object -Parallel {
    		function Show{
    			param($s)
    			$s
    		}
    		Show $_
    	}
    The code used uses a "PSTask" named runspace for the threads.


    \_(ツ)_/


    • Upravený jrvModerator úterý 22. října 2019 0:10
    • Označen jako odpověď Ian3 středa 23. října 2019 2:51
    úterý 22. října 2019 0:09
    Moderátor