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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With