关于powershell:即使在Receive-Job之后,“ HasMoreData”也是如此

“HasMoreData” is true even after Receive-Job

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

1
Start-Job {"Hello"}

我通过Get-Job检查:

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

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

1
2
Receive-Job 1
Get-Job

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

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

例子:

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

我是否可以绕过此(错误)行为,以便属性HasMoreData切换为False,除非我指定-keep

谢谢!

更新:似乎是所有使用-AsJob参数进行的调用。 如果你跑

1
Start-Job {Test-Connection .}

它起作用(Receive-Job之后" HasMoreData"变为False),但是

1
Test-Connection . -AsJob

才不是。


简短答案:

这是PowerShell 2.0中的错误。

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

长答案:

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

我还看到了说明Start-Job由本地IPC起作用的文档,而-AsJob与指定计算机的WinRM服务建立了连接,即使它是本地主机,也必须在本地计算机和目标计算机上启用PSRemoting (s)。同样,它不是那么简单。我发现我可以在本地计算机上使用-AsJob开关运行作业,同时禁用WinRM和PSRemoting。

无论如何,PowerShell都会以两种JobType(PSWmiJob或PSRemotingJob)之一启动作业。这是违反直觉的,因为在本地运行后台作业的Start-Job总是创建PSRemotingJob,而-AsJob通常创建PSWmiJob,除非与Invoke-Command一起使用时,Invoke-Command总是启动PSRemoting作业,而不管命令是否在远程计算机或本地主机上调用。

看看下面的会话记录,其中我以各种方式创建了作业。我用以下三个命令进行了测试:Get-WMIObject,当用-AsJob和ComputerName调用时,它在远程计算机上运行; Test-Connection,当用-AsJob调用时总是在本地运行(-ComputerName指定要对哪台计算机执行ping操作,而不是在何处运行命令);和Get-ChildItem,它没有-AsJob参数。我在远程计算机和本地计算机上都使用Start-Job,Invoke-Command -AsJob和本机-AsJob开关(对于具有该命令的命令)启动了每个作业。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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对象中。不管创建作业的方式如何,以及无论该命令在本地还是远程运行,在Job-Job之后,如果JobType为PSRemotingJob,则HasMoreData属性将设置为False,而如果JobType为PSWmiJob,则该属性将保持True。

据我所知,没有办法在PSWmiJob上将HasMoreData设置为False。 Stop-Job不会执行此操作,重新启动WinRM不会执行此操作,并且该属性为只读。


看到以下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
PS C:\\dell> Test-Connection . -AsJob

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
2      Job2            WmiJob          Running       True            .                    Test-Connection


PS C:\\dell> Get-Job

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
2      Job2            WmiJob          Completed     True            .                    Test-Connection


PS C:\\dell> Get-Job Job2 | fl


StatusMessage :
HasMoreData   : True
Location      : .
Command       : Test-Connection
JobStateInfo  : Completed
Finished      : System.Threading.ManualResetEvent
InstanceId    : d16afbe0-31f7-4189-8d2a-30ede40645c4
Id            : 2
Name          : Job2
ChildJobs     : {Job3}
PSBeginTime   : 7/16/2013 10:22:58 PM
PSEndTime     : 7/16/2013 10:22:58 PM
PSJobTypeName : WmiJob
Output        : {}
Error         : {}
Progress      : {}
Verbose       : {}
Debug         : {}
Warning       : {}
State         : Completed



PS C:\\dell> Get-Job Job3

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
3      Job3                            Completed     True            .


PS C:\\dell> Get-Job Job3 | Receive-Job

Source        Destination     IPV4Address      IPV6Address                              Bytes    Time(ms)
------        -----------     -----------      -----------                              -----    --------
W4-G9W... localhost       127.0.0.1                                                 32       0
W4-G9W... localhost       127.0.0.1                                                 32       0
W4-G9W... localhost       127.0.0.1                                                 32       0
W4-G9W... localhost       127.0.0.1                                                 32       0


PS C:\\dell> Get-Job Job2 | fl


StatusMessage :
HasMoreData   : False
Location      : .
Command       : Test-Connection
JobStateInfo  : Completed
Finished      : System.Threading.ManualResetEvent
InstanceId    : d16afbe0-31f7-4189-8d2a-30ede40645c4
Id            : 2
Name          : Job2
ChildJobs     : {Job3}
PSBeginTime   : 7/16/2013 10:22:58 PM
PSEndTime     : 7/16/2013 10:22:58 PM
PSJobTypeName : WmiJob
Output        : {}
Error         : {}
Progress      : {}
Verbose       : {}
Debug         : {}
Warning       : {}
State         : Completed



PS C:\\dell> Get-Job Job3

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
3      Job3                            Completed     False           .

您会看到Job2是顶级作业,并且创建了一个名为Job3的子作业。那是实际行动发生的地方。

您可以接收子作业并检查HasMoreData是否仍然设置吗?