Search code examples
powershellpowershell-3.0

Return data from Powershell jobs without the Job-Information


i'm running a job which looks like this

$myjob =
{
  # regerate some $data
  return $data
}

I start and receive my job like this:

Start-Job -ScriptBlock $myjob -Name "job1"
Wait-Job -Name "job1"
$result = Receive-Job -Job "job1"

Now i want my $result to contain ONLY the $data which was returned. However, when inspecting $result besides of the $data i see much more information which I don't want to be included in my $data array. The messed-up data starts something like this:

(Returned Data:)

State         : Running
HasMoreData   : True
StatusMessage : 
Location      : localhost
Command       :  # regerate some $data
                 return $data
JobStateInfo  : Running
Finished      : System.Threading.ManualResetEvent
InstanceId    : f7c63b33-d270-4fa8-8042-111edf9d86a6
Id            : 270
Name          : job1
ChildJobs     : {Job271}
PSBeginTime   : 03.12.2012 14:06:26
PSEndTime     : 
PSJobTypeName : BackgroundJob
Output        : {}
Error         : {}
Progress      : {}
Verbose       : {}
Debug         : {}
Warning       : {}

this repeats over and over again like 20 times. After that my real $data is listed. However: iterateing over the $result array is not possible that way. What can i do?


Solution

  • You are falling prey to a common misunderstanding about powershell: All uncaptured output in a script is returned to the caller, not just the arguments to "return." Example:

    ps> $s = {
        1..3 # write 1,2,3 to output stream
        return 4 # write 4 to output stream, then exit scriptblock!
        5 # won't be output
        return 6 # won't be output either
    }
    
    ps> & $s
    1
    2
    3
    4
    

    The return statement is used to exit a function early, and to optionally write one or more objects to the output stream (in addition to other outputs already emitted.)

    If you don't want something to get output, then use one of the follow syntaxes:

    $null = mycommand 
    mycommand > $null
    [void] (mycommand)
    

    The reason you're seeing two extra "job" objects in your output is that both start-job and wait-job return the job object created and waited for, respectively. The reason for this is to allow pipelining:

    $results = start-job { ... } | wait-job | receive-job 
    

    What's happening here? Well, start-job creates a job and passes it to wait-job which waits until the job is complete, then passes the job to receive-job, which returns the results and is finally assigned to $results.

    Following?