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日 19: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日 0:10
    • 已标记为答案 Ian3 2019年10月23日 2:51
    2019年10月22日 0: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日 19: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日 15:05
    2019年10月21日 3:38
  • The function must be included in the scriptblocks as always.

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


    \_(ツ)_/

    2019年10月21日 3: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日 4: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日 15:10
    2019年10月21日 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?


    \_(ツ)_/

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


    \_(ツ)_/

    2019年10月21日 18: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日 18:52
    2019年10月21日 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.


    \_(ツ)_/

    2019年10月21日 19: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日 0:10
    • 已标记为答案 Ian3 2019年10月23日 2:51
    2019年10月22日 0:09
    版主