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

  • 問題

  • 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

    2019年10月20日 下午 07:10

解答

  • 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.


    \_(ツ)_/


    • 已編輯 jrvModerator 2019年10月22日 上午 12:10
    • 已標示為解答 Ian3 2019年10月23日 上午 02:51
    2019年10月22日 上午 12:09
    版主

所有回覆

  • 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.


    \_(ツ)_/

    2019年10月20日 下午 07:46
    版主
  • 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 $_ }

    • 已編輯 JS2010 2019年10月21日 下午 03:05
    2019年10月21日 上午 03:38
  • The function must be included in the scriptblocks as always.

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


    \_(ツ)_/

    2019年10月21日 上午 03:51
    版主
  • 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


    \_(ツ)_/

    2019年10月21日 上午 04:02
    版主
  • 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

    • 已編輯 JS2010 2019年10月21日 下午 03:10
    2019年10月21日 下午 02: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?


    \_(ツ)_/

    2019年10月21日 下午 05:55
    版主
  • It would be almost like running a pre-defined function in the foreach.
    2019年10月21日 下午 06: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.


    \_(ツ)_/

    2019年10月21日 下午 06:32
    版主
  • 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.

    • 已編輯 JS2010 2019年10月21日 下午 06:52
    2019年10月21日 下午 06: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.


    \_(ツ)_/

    2019年10月21日 下午 07:22
    版主
  • 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.


    \_(ツ)_/


    • 已編輯 jrvModerator 2019年10月22日 上午 12:10
    • 已標示為解答 Ian3 2019年10月23日 上午 02:51
    2019年10月22日 上午 12:09
    版主