1

I was following the example given in post

to call a simple function in parallel. I am getting the error but unable to figure out why.

Below is the code block.

function run-thescript 
{
  param (
        $Parameter1,
        $Parameter2
    )
#Write-Host 'inside the outer function'
Write-Output "the first parameter is $Parameter1 and second is $Parameter2"
}

$cmd = {
  param($a, $b)
  Write-Host $a $b
  run-thescript -Parameter1 $a -Parameter2 $b
}

Start-Job -ScriptBlock $cmd -ArgumentList @('input1','input2')

Error thrown after running

Get-Job | % { Receive-Job $_.Id; Remove-Job $_.Id }

is

The term 'run-thescript' 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.
    + CategoryInfo          : ObjectNotFound: (run-thescript:String) [], Comma 
   ndNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : localhost
rainu
  • 733
  • 2
  • 12
  • 26
  • `Start-Job` start completely new PowerShell process with completely new separare PowerShell runspace, which know nothing about `run-thescript`. – user4003407 Jul 24 '19 at 18:10
  • the post you link to does NOT cover passing a _function_ to a scriptblock. [*grin*] you need to use something like `$function:Run-TheScript` to get that into the new scope. – Lee_Dailey Jul 24 '19 at 18:13
  • Thank you, the function scope was the problem, a work around for this seem liking adding the function in another .ps1 file and calling the ps1 with function definition in Scriptblock so that function will be in scope, that worked in my case. – rainu Jul 25 '19 at 03:21

1 Answers1

1

The issue is that the Job scope (just like a new PowerShell window) does not know about the functions but, there are two ways to do this in my opinion, the functions need to be delcared after the param statement so something like $functions+$cmd will not work with the provided example, as a workaround you could use $using:variable instead of Param() to transport arguments to the Job scope or inject the functions themself as an argument.

examples using $using: below:

# -----------------------------------------------------------
# *                                                 Functions
# -----------------------------------------------------------

# -----------------------------------------------------------
# *                                             run-thescript

function run-thescript 
{
    param (
        $Parameter1,
        $Parameter2
    )

    Write-Output "the first parameter is $Parameter1 and second is $Parameter2"
}

# -----------------------------------------------------------
# *                                                 Execution
# -----------------------------------------------------------

# -----------------------------------------------------------
# *                                         Capture functions

# specify the functions here
$Functions = @(
    'run-thescript'
    #"some-function"
    #"other-function"
)

# This will look for the specified functions and store them in the $functions variable.
$Functions = $Functions | ForEach-Object {
    Write-Verbose -Message "Processing $($PSItem)"
    (Get-Item -Path "Function:\$($PSItem)").ScriptBlock.StartPosition.Content
}

# -----------------------------------------------------------
# *                                         Parse and Execute

$a = 'input1'
$b = 'input2'

$ScriptBlock = {
    $a = $using:a
    $b = $using:b
    Write-Host $a $b
    run-thescript -Parameter1 $a -Parameter2 $b
}

Start-Job -ScriptBlock ([Scriptblock]::Create($Functions + $ScriptBlock))
SteloNLD
  • 541
  • 3
  • 12
  • Thanks, this solution helps to keep the function definition and rest of the code in one file. Though of moving the definition to another ps1 file and call it in the Scriptblock to get it in scope. – rainu Jul 25 '19 at 03:26
  • if I have to start another job with varying parameter , do I need to have another ScriptBlock ? – rainu Jul 27 '19 at 08:13
  • You can use the same script block, just make sure that the $a en $b variable have the required value when calling `Start-Job`. – SteloNLD Jul 28 '19 at 18:09