Background Job in Powershell
Asked Answered
B

2

7

I'm trying to run a job in a background which is a .exe with parameters and the destination has spaces. For example:

$exec = "C:\Program Files\foo.exe"

and I want to run this with parameters:

foo.exe /param1 /param2, etc.

I know that Start-Job does this but I've tried tons of different combinations and it either gives me an error because of the white space or because of the parameters. Can someone help me out with the syntax here? I need to assume that $exec is the path of the executable because it is part of a configuration file and could change later on.

Bathurst answered 4/1, 2012 at 1:31 Comment(0)
D
8

One way to do this is use a script block with a param block.

If there is a single argument with a space in it such as a file/folder path it should be quoted to treat it as a single item. The arguments are an array passed to the script block.

This example uses a script block but you can also use a PowerShell script using the -FilePath parameter of the Start-Job cmdlet instead of the -ScriptBlock parameter.

Here is another example that has arguments with spaces:

$scriptBlock = {
    param (
        [string] $Source,
        [string] $Destination
    )
    $output = & xcopy $Source $Destination 2>&1
    return $output
}

$job = Start-Job -scriptblock $scriptBlock -ArgumentList 'C:\My Folder', 'C:\My Folder 2'
Wait-Job $job
Receive-Job $job

Here is an example using the $args built-in variable instead of the param block.

$scriptBlock = {
    $output = & xcopy $args 2>&1
    return $output
}

$path1 = "C:\My Folder"
$path2 = "C:\My Folder 2"

"hello world" | Out-File -FilePath  "$path1\file.txt"

$job = Start-Job -scriptblock $scriptBlock -ArgumentList $path1, $path2
Wait-Job $job
Receive-Job $job
Doscher answered 4/1, 2012 at 1:51 Comment(2)
Thanks for the help! What does the 2>&1 mean?Bathurst
@Bathurst Ah yes that will redirect the standard error stream (2) to the standard out stream (1). This ensures you'll receive all text from the executable from the Receive-Job cmdlet. Typically what I do in the background job is capture the output of an executable $out = xcopy $a $b 2>&1 then check if the exit code ($LASTEXITCODE) is non-zero and if so throw the captured text as an exception message: throw $out.Doscher
L
3

Andy's trick generally works very well. If you have parameter sets, or otherwise want to move complex information into the job, you can also try this technique:

$jobArgs = @{Source="foo"; Destination="bar"}
$jobArgs  |Export-CliXml -Path $env:\Temp\MyArgs.clixml

and in the job...

Start-Job {
.... $jobArgs =  Import-CliXml -Path $env:\Temp\MyArgs.clixml
} | Wait-Job | Receive-Job

I use both approaches routinely.

I use -ArgumentList / ScriptBlock parameters when:

  • I am not dealing with parameter sets
  • I'm using an In-Memory Job (like the -AsJob capability in ShowUI or WPK) where the arguments are real objects, and they cannot die
  • I'm running in a user context where I can run a job, but can't store to disk (web servers, ISO compliant labs, etc)

If I need complex arguments, and they don't need to be passed in memory (or its otherwise convenient to have them on disk later), I'll use the hashtable approach.

Hope this Helps

Labelle answered 4/1, 2012 at 4:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.