"HasMoreData" is true even after Receive-Job "HasMoreData" is true even after Receive-Job powershell powershell

"HasMoreData" is true even after Receive-Job


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_gjbId 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_bios11 Start-Job -ScriptBlock {Test-Connection .}                                            localhost PSRemotingJob True        Completed Test-Connection .13 Test-Connection . -AsJob                                                              .         PSWmiJob      True        Completed Test-Connection15 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-Null07-17-13 19:47:14.52 C:\Users\ainbar» gjb|ft -a $fmt_gjbId 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_bios11 Start-Job -ScriptBlock {Test-Connection .}                                            localhost PSRemotingJob False       Completed Test-Connection .13 Test-Connection . -AsJob                                                              .         PSWmiJob      True        Completed Test-Connection15 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.


See this output:

PS C:\dell> Test-Connection . -AsJobId     Name            PSJobTypeName   State         HasMoreData     Location             Command--     ----            -------------   -----         -----------     --------             -------2      Job2            WmiJob          Running       True            .                    Test-ConnectionPS C:\dell> Get-JobId     Name            PSJobTypeName   State         HasMoreData     Location             Command--     ----            -------------   -----         -----------     --------             -------2      Job2            WmiJob          Completed     True            .                    Test-ConnectionPS C:\dell> Get-Job Job2 | flStatusMessage :HasMoreData   : TrueLocation      : .Command       : Test-ConnectionJobStateInfo  : CompletedFinished      : System.Threading.ManualResetEventInstanceId    : d16afbe0-31f7-4189-8d2a-30ede40645c4Id            : 2Name          : Job2ChildJobs     : {Job3}PSBeginTime   : 7/16/2013 10:22:58 PMPSEndTime     : 7/16/2013 10:22:58 PMPSJobTypeName : WmiJobOutput        : {}Error         : {}Progress      : {}Verbose       : {}Debug         : {}Warning       : {}State         : CompletedPS C:\dell> Get-Job Job3Id     Name            PSJobTypeName   State         HasMoreData     Location             Command--     ----            -------------   -----         -----------     --------             -------3      Job3                            Completed     True            .PS C:\dell> Get-Job Job3 | Receive-JobSource        Destination     IPV4Address      IPV6Address                              Bytes    Time(ms)------        -----------     -----------      -----------                              -----    --------W4-G9W... localhost       127.0.0.1                                                 32       0W4-G9W... localhost       127.0.0.1                                                 32       0W4-G9W... localhost       127.0.0.1                                                 32       0W4-G9W... localhost       127.0.0.1                                                 32       0PS C:\dell> Get-Job Job2 | flStatusMessage :HasMoreData   : FalseLocation      : .Command       : Test-ConnectionJobStateInfo  : CompletedFinished      : System.Threading.ManualResetEventInstanceId    : d16afbe0-31f7-4189-8d2a-30ede40645c4Id            : 2Name          : Job2ChildJobs     : {Job3}PSBeginTime   : 7/16/2013 10:22:58 PMPSEndTime     : 7/16/2013 10:22:58 PMPSJobTypeName : WmiJobOutput        : {}Error         : {}Progress      : {}Verbose       : {}Debug         : {}Warning       : {}State         : CompletedPS C:\dell> Get-Job Job3Id     Name            PSJobTypeName   State         HasMoreData     Location             Command--     ----            -------------   -----         -----------     --------             -------3      Job3                            Completed     False           .

You see that the Job2 is the toplevel job and it has a child job created with the name Job3. That is where the actual action is taking place.

Can you receive the child job and check if the HasMoreData is still set?