Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"HasMoreData" is true even after Receive-Job

I create a simple background job in Powershell:

Start-Job {"Hello"}

I check with Get-Job:

    Id        Name         State         HasMoreData      Location       Command
    --        ----         -----         -----------      --------       -------
    1         Job1         Completed     True             localhost      "Hello"

Next, I simply receive the output, and run Get-Job again

Receive-Job 1
Get-Job

I can see that "HasMoreData" is now false, because I didn't specify the -keep parameter.

HOWEVER: it seems that whenever I start a job, not with Start-Job or Invoke-Command, that this "HasMoreData" parameter does not change to False.

Examples:

Get-WMIObject win32_bios -AsJob
Test-Connection . -AsJob

Can I bypass this (wrong) behaviour, so that the property HasMoreData switches to False, unless I specify -keep?

Thanks!

Update: it seems to be for all calls made with the -AsJob parameter. If you run

Start-Job {Test-Connection .}

it works ("HasMoreData" becomes False after Receive-Job), but

Test-Connection . -AsJob

does not.

like image 275
Joost Avatar asked Jun 07 '12 14:06

Joost


1 Answers

Short answer:

It's a bug in PowerShell 2.0.

It works fine for Blaine because he's using PowerShell 3, I'd put money on it.


Long answer:

The Start-Job cmdlet and the -AsJob switch work differently. Documentation usually explains that Start-Job is intended to run background jobs locally whereas -AsJob is intended to start jobs with commands that run on remote computers but creates the job object locally. While that's generally true, -AsJob can also be used to run jobs locally, and depending on the command, it's sometimes not even capable of running the command on a remote computer. For example, Get-WMIObject invoked with -AsJob and -ComputerName runs the command on the specified remote computer, whereas Test-Connection invoked with -AsJob and -Computername runs the command locally and pings the specified computer.

I've also seen documentation that explains that Start-Job works by local IPC, whereas -AsJob makes a connection to the WinRM service of the specified computer, even if it's the localhost, and that PSRemoting must be enabled on the local and target computer(s). Again, it's not quite that straightforward. I've found that I can run jobs with the -AsJob switch on the localhost with WinRM and PSRemoting both disabled.

In any case, PowerShell starts jobs as one of two JobTypes, PSWmiJob or PSRemotingJob. This is counter-intuitive, because Start-Job, which runs background jobs locally, always creates a PSRemotingJob, whereas -AsJob usually creates a PSWmiJob, except when it's used with Invoke-Command, which always starts a PSRemoting job regardless of whether the command is invoked on a remote computer or the localhost.

Take a look at the following session transcript, in which I created jobs in the varying ways. I tested with three commands: Get-WMIObject, which runs on a remote computer when invoked with -AsJob and ComputerName; Test-Connection, which always runs locally when invoked with -AsJob (-ComputerName specifies which computer to ping, not where to run the command); and Get-ChildItem, which doesn't have an -AsJob parameter. I started jobs for each one using Start-Job, Invoke-Command -AsJob on both a remote computer and the local machine, and the native -AsJob switch (for commands that have it).

The purpose of the | %{$_.Name = '<the command preceding the pipe symbol>'} at the end of each command is to name each job as the command that created it, so it's easier to see in the output which job corresponds to each command. It has no effect on the operation of the jobs, it just renames each job to a more meaningful name immediately after creating it.

What you'll see is that after all the jobs are received (rcjb * 2>&1|Out-Null receives them all at once and suppresses output), the HasMoreData property of PSRemotingJob objects is set to False whether they were created by Start-Job or -AsJob, but the HasMoreData property of PSWmiJob objects remains True. Beyond the examples I've reproduced here, I've found that this holds true consistently.

07-17-13 19:44:56.30 C:\Users\ainbar» Invoke-Command -ComputerName . -ScriptBlock {Get-WMIObject win32_bios} -AsJob | %{$_.Name = 'Invoke-Command -ComputerName . -ScriptBlock {Get-WMIObject win32_bios} -AsJob'}
07-17-13 19:44:56.43 C:\Users\ainbar» Invoke-Command -ComputerName ai8460p -ScriptBlock {Get-WMIObject win32_bios} -AsJob | %{$_.Name = 'Invoke-Command -ComputerName ai8460p -ScriptBlock {Get-WMIObject win32_bios} -AsJob'}
07-17-13 19:44:56.46 C:\Users\ainbar» Start-Job -ScriptBlock {Test-Connection .} | %{$_.Name = 'Start-Job -ScriptBlock {Test-Connection .}'}
07-17-13 19:44:57.13 C:\Users\ainbar» Test-Connection . -AsJob | %{$_.Name = 'Test-Connection . -AsJob '}
07-17-13 19:44:57.14 C:\Users\ainbar» Invoke-Command -ComputerName . -ScriptBlock {Test-Connection .} -AsJob | %{$_.Name = 'Invoke-Command -ComputerName . -ScriptBlock {Test-Connection .}'}
07-17-13 19:44:57.18 C:\Users\ainbar» Invoke-Command -ComputerName ai8460p -ScriptBlock {Test-Connection .} -AsJob | %{$_.Name = 'Invoke-Command -ComputerName ai8460p -ScriptBlock {Test-Connection .} -AsJob'}
07-17-13 19:44:57.20 C:\Users\ainbar» Start-Job -ScriptBlock {Get-ChildItem C:\} | %{$_.Name = 'Start-Job -ScriptBlock {Get-ChildItem C:\}'}
07-17-13 19:44:57.80 C:\Users\ainbar» Invoke-Command -ComputerName . -ScriptBlock {Get-ChildItem C:\} -AsJob | %{$_.Name = 'Invoke-Command -ComputerName . -ScriptBlock {Get-ChildItem C:\} -AsJob'}
07-17-13 19:44:57.82 C:\Users\ainbar» Invoke-Command -ComputerName ai8460p -ScriptBlock {Get-ChildItem C:\} -AsJob | %{$_.Name = 'Invoke-Command -ComputerName ai8460p -ScriptBlock {Get-ChildItem C:\} -AsJob'}
07-17-13 19:44:57.84 C:\Users\ainbar» $fmt_gjb = 'Id','Name','Location',@{l="JobType";e={$_.GetType().name}},@{l='HasMoreData';e={"$($_.HasMoreData)"}},'State','Command'
07-17-13 19:46:21.36 C:\Users\ainbar» gjb|ft -a $fmt_gjb

Id Name                                                                                  Location  JobType       HasMoreData     State Command
-- ----                                                                                  --------  -------       -----------     ----- -------
 1 Start-Job -ScriptBlock {Get-WMIObject win32_bios}                                     localhost PSRemotingJob True        Completed Get-WMIObject win32_bios
 3 Get-WMIObject win32_bios -AsJob                                                       localhost PSWmiJob      True        Completed Get-WMIObject
 5 Get-WMIObject win32_bios -AsJob -ComputerName ai8460p                                 ai8460p   PSWmiJob      True        Completed Get-WMIObject
 7 Invoke-Command -ComputerName . -ScriptBlock {Get-WMIObject win32_bios} -AsJob         localhost PSRemotingJob True        Completed Get-WMIObject win32_bios
 9 Invoke-Command -ComputerName ai8460p -ScriptBlock {Get-WMIObject win32_bios} -AsJob   ai8460p   PSRemotingJob True        Completed Get-WMIObject win32_bios
11 Start-Job -ScriptBlock {Test-Connection .}                                            localhost PSRemotingJob True        Completed Test-Connection .
13 Test-Connection . -AsJob                                                              .         PSWmiJob      True        Completed Test-Connection
15 Invoke-Command -ComputerName . -ScriptBlock {Test-Connection .}                       localhost PSRemotingJob True        Completed Test-Connection .
17 Invoke-Command -ComputerName ai8460p -ScriptBlock {Test-Connection .} -AsJob          ai8460p   PSRemotingJob True        Completed Test-Connection .
19 Start-Job -ScriptBlock {Get-ChildItem C:\}                                            localhost PSRemotingJob True        Completed Get-ChildItem C:\
21 Invoke-Command -ComputerName . -ScriptBlock {Get-ChildItem C:\} -AsJob                localhost PSRemotingJob True        Completed Get-ChildItem C:\
23 Invoke-Command -ComputerName ai8460p   -ScriptBlock {Get-ChildItem C:\} -AsJob        ai8460p   PSRemotingJob True        Completed Get-ChildItem C:\


07-17-13 19:46:37.94 C:\Users\ainbar» rcjb * 2>&1|Out-Null
07-17-13 19:47:14.52 C:\Users\ainbar» gjb|ft -a $fmt_gjb

Id Name                                                                                  Location  JobType       HasMoreData     State Command
-- ----                                                                                  --------  -------       -----------     ----- -------
 1 Start-Job -ScriptBlock {Get-WMIObject win32_bios}                                     localhost PSRemotingJob False       Completed Get-WMIObject win32_bios
 3 Get-WMIObject win32_bios -AsJob                                                       localhost PSWmiJob      True        Completed Get-WMIObject
 5 Get-WMIObject win32_bios -AsJob -ComputerName ai8460p                                 ai8460p   PSWmiJob      True        Completed Get-WMIObject
 7 Invoke-Command -ComputerName . -ScriptBlock {Get-WMIObject win32_bios} -AsJob         localhost PSRemotingJob False       Completed Get-WMIObject win32_bios
 9 Invoke-Command -ComputerName ai8460p -ScriptBlock {Get-WMIObject win32_bios} -AsJob   ai8460p   PSRemotingJob False       Completed Get-WMIObject win32_bios
11 Start-Job -ScriptBlock {Test-Connection .}                                            localhost PSRemotingJob False       Completed Test-Connection .
13 Test-Connection . -AsJob                                                              .         PSWmiJob      True        Completed Test-Connection
15 Invoke-Command -ComputerName . -ScriptBlock {Test-Connection .}                       localhost PSRemotingJob False       Completed Test-Connection .
17 Invoke-Command -ComputerName ai8460p -ScriptBlock {Test-Connection .} -AsJob          ai8460p   PSRemotingJob False       Completed Test-Connection .
19 Start-Job -ScriptBlock {Get-ChildItem C:\}                                            localhost PSRemotingJob False       Completed Get-ChildItem C:\
21 Invoke-Command -ComputerName . -ScriptBlock {Get-ChildItem C:\} -AsJob                localhost PSRemotingJob False       Completed Get-ChildItem C:\
23 Invoke-Command -ComputerName ai8460p   -ScriptBlock {Get-ChildItem C:\} -AsJob        ai8460p   PSRemotingJob False       Completed Get-ChildItem C:\


07-17-13 19:47:35.29 C:\Users\ainbar»

Bottom line: The bug is in the PSWmiJob object. Regardless of which way the job was created, and regardless of whether the command runs locally or remotely, after a Receive-Job the HasMoreData property is set to False if the JobType is PSRemotingJob, but remains True if the JobType is PSWmiJob.

As far as I can tell, there is no way to set HasMoreData to False on a PSWmiJob. Stop-Job won't do it, restarting WinRM won't do it, and the property is read-only.

like image 154
Adi Inbar Avatar answered Oct 01 '22 02:10

Adi Inbar