"HasMoreData"即使在接收工作之后也是如此 [英] "HasMoreData" is true even after Receive-Job

查看:60
本文介绍了"HasMoreData"即使在接收工作之后也是如此的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Powershell中创建一个简单的后台作业:

Start-Job {"Hello"}

我通过Get-Job进行检查:

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

接下来,我只接收输出,然后再次运行Get-Job

Receive-Job 1
Get-Job

我可以看到"HasMoreData"现在为假,因为我没有指定-keep参数.

但是:似乎每当我开始工作而不是不使用Start-JobInvoke-Command时,此"HasMoreData"参数都不会更改为False.

示例:

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

除非我指定-keep,否则我可以绕过这种(错误的)行为,以便属性HasMoreData切换为False吗?

谢谢!

更新:它似乎适用于所有使用-AsJob参数进行的通话.如果您运行

Start-Job {Test-Connection .}

它有效(在Receive-Job之后,"HasMoreData"变为False),但是

Test-Connection . -AsJob

没有.

解决方案

简短答案:

这是PowerShell 2.0中的错误.

对于Blaine来说,它工作正常,因为他使用的是PowerShell 3,我会花钱在上面.


长答案:

开始作业 cmdlet和 -AsJob 开关的工作方式不同.文档通常说明 Start-Job 用于在本地运行后台作业,而 -AsJob 用于使用在远程计算机上运行但在本地创建作业对象的命令启动作业.尽管通常是这样,但是 -AsJob 也可以用于在本地运行作业,并且根据命令的不同,有时甚至无法在远程计算机上运行命令.例如,用 -AsJob -ComputerName 调用的 Get-WMIObject 在指定的远程计算机上运行命令,而 Test-Connection -AsJob -Computername 一起调用会在本地运行命令并ping指定的计算机.

我还看过文档,它解释了 Start-Job 由本地IPC进行工作,而 -AsJob 可以连接到指定计算机的WinRM服务,甚至如果是本地主机,则必须在本地和目标计算机上启用PSRemoting.同样,它不是那么简单.我发现我可以使用本地计算机上的 -AsJob 开关运行作业,同时禁用WinRM和PSRemoting.

在任何情况下,PowerShell都会以两种JobTypes(PSWmiJob或PSRemotingJob)之一启动作业.这是违反直觉的,因为在本地运行后台作业的 Start-Job 总是创建PSRemotingJob,而 -AsJob 通常创建一个PSWmiJob,除非与 Invoke-Command ,无论命令是在远程计算机还是在本地主机上调用,该命令始终会启动PSRemoting作业.

看看下面的会话记录,其中我以各种方式创建了作业.我用以下三个命令进行了测试: Get-WMIObject ,当使用 -AsJob ComputerName 调用时,该命令将在远程计算机上运行; 测试连接,当使用 -AsJob 调用时,该连接始终在本地运行( -ComputerName 指定要ping的计算机,而不是在哪里运行命令) ;和 Get-ChildItem ,该参数没有 -AsJob 参数.我使用远程计算机和本地计算机上的 Start-Job Invoke-Command -AsJob 和本机 -AsJob 来启动每个作业. strong>开关(用于具有此功能的命令).

在每个命令末尾| %{$_.Name = '<the command preceding the pipe symbol>'}的目的是将每个作业命名为创建它的命令,因此在输出中更容易看到哪个作业对应于每个命令.它对作业的操作没有影响,只是在创建作业后立即将每个作业重命名为一个更有意义的名称.

您将看到的是,在接收到所有作业(rcjb * 2>&1|Out-Null一次接收所有作业并禁止输出)之后,无论它们是由 Start-创建的,PSRemotingJob对象的HasMoreData属性都设置为False. Job -AsJob ,但PSWmiJob对象的HasMoreData属性保持为True.除了我在此处复制的示例以外,我发现这始终如一.

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»

底线:该错误位于PSWmiJob对象中.无论创建作业的方式如何,以及是否在本地运行还是远程运行命令,在 Receive-Job 之后,如果JobType为PSRemotingJob,则HasMoreData属性设置为False,但如果JobType是PSWmiJob.

据我所知,没有办法在PSWmiJob上将HasMoreData设置为False. 停止作业不会执行此操作,重新启动WinRM不会执行此操作,并且该属性是只读的.

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.

这篇关于"HasMoreData"即使在接收工作之后也是如此的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆