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
3
  • Start-Job start completely new PowerShell process with completely new separare PowerShell runspace, which know nothing about run-thescript. Commented Jul 24, 2019 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. Commented Jul 24, 2019 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. Commented Jul 25, 2019 at 3:21

1 Answer 1

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))
Sign up to request clarification or add additional context in comments.

3 Comments

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.
if I have to start another job with varying parameter , do I need to have another ScriptBlock ?
You can use the same script block, just make sure that the $a en $b variable have the required value when calling Start-Job.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.