How to pass parameters to a PS script invoked through Start-Job?

498 Views Asked by At

I want to use start-job to run a .ps1 script requiring a parameter. Here's the script file:

#Test-Job.ps1 
Param (
[Parameter(Mandatory=$True)][String]$input
)

$output = "$input to output"

return $output

and here is how I am running it:

$input = "input"
Start-Job -FilePath 'C:\PowerShell\test_job.ps1' -ArgumentList $input -Name "TestJob"
Get-Job -name "TestJob" | Wait-Job | Receive-Job
Get-Job -name "TestJob" | Remove-Job

Run like this, it returns " to output", so $input is null in the script run by the job.

I've seen other questions similar to this, but they mostly use -Scriptblock in place of -FilePath. Is there a different method for passing parameters to files through Start-Job?

1

There are 1 best solutions below

0
On BEST ANSWER

tl;dr

  • $input is an automatic variable (value supplied by PowerShell) and shouldn't be used as a custom variable.

  • Simply renaming $input to, say, $InputObject solves your problem.


As Lee_Dailey notes, $input is an automatic variable and shouldn't be assigned to (it is automatically managed by PowerShell to provide an enumerator of pipeline input in non-advanced scripts and functions).

Regrettably and unexpectedly, several automatic variables, including $input, can be assigned to: see this answer.

$input is a particularly insidious example, because if you use it as a parameter variable, any value you pass to it is quietly discarded, because in the context of a function or script $input invariably is an enumerator for any pipeline input.

Here's a simple example to demonstrate the problem:

PS> & { param($input) "[$input]" } 'hi'
 # !! No output - the argument was quietly discarded.

That the built-in definition of $input takes precedence can be demonstrated as follows:

PS> 'ho' | & { param($input) "[$input]" } 'hi'
ho # !! pipeline input took precedence

While you can technically get away with using $input as a regular variable (rather than a parameter variable) as long as you don't cross scope boundaries, custom use of $input should still be avoided:

& {
  $input = 'foo'   # TO BE AVOIDED
  "[$input]"       # Technically works: -> '[foo]'
  & { "[$input]" } # FAILS, due to child scope: -> '[]'
}