如何使用-AsJob开关接收测试连接中的错误

时间:2018-07-26 15:39:25

标签: multithreading powershell start-job

我正在设置一个监视脚本,该脚本将在数据包失败时ping IP并发送电子邮件。我决定使用Test-Connection。下面是示例代码:

代码1

$IPList = @("192.168.0.1","172.217.161.15")
Test-Connection -ComputerName $IPList -BufferSize 4 -Count 1 -AsJob -ErrorAction Stop
Get-Job | Wait-Job | Receive-Job

所以我得到的结果是:

Source        Destination     IPV4Address      IPV6Address                              Bytes    Time(ms) 
------        -----------     -----------      -----------                              -----    -------- 
BLR-AA200906  172.217.161.15                                                            4        55       
BLR-AA200906  192.168.0.1                                                               4                 

应该认为192系列IP会引发错误。您会看到Time(ms)列为空。

代码2

$IPList = @("192.168.0.1","172.217.161.15")
foreach ($IP in $IPList)
{
    Start-job -ScriptBlock {Test-Connection -ComputerName $Args[0] -BufferSize 4 -Count 1 -ErrorAction Stop} -ArgumentList $IP
}
Get-Job | Wait-Job | Receive-Job

如果我这样做,将会抛出一个错误,我很容易抓住

Testing connection to computer '192.168.0.1' failed: Error due to lack of resources
    + CategoryInfo          : ResourceUnavailable: (192.168.0.1:String) [Test-Connection], PingException
    + FullyQualifiedErrorId : TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand
    + PSComputerName        : localhost

问题

这使我想到了我的问题。如何接收/捕获Code1中引发的错误消息?区别在于我使用的是-AsJob,它比在foreach循环中分散工作要高效得多。

PS版本为5.1

2 个答案:

答案 0 :(得分:1)

重要的是要区分您的代码示例在做不同的事情,Code1正在完成一项工作并运行了x个测试连接。 Code2正在加速x每个测试1个连接的作业数。

我不知道使用-asjob从测试连接中消除错误的方法,但是另一种方法是使用statuscode属性。 11010Error due to lack of resources的状态代码,当测试连接未收到主机(又名Request Timed Out)的响应时,就会出现$IPList = @("192.168.254.1","172.217.161.15") $StatusCodes = @{ [uint32]0 = 'Success' [uint32]11001 = 'Buffer Too Small' [uint32]11002 = 'Destination Net Unreachable' [uint32]11003 = 'Destination Host Unreachable' [uint32]11004 = 'Destination Protocol Unreachable' [uint32]11005 = 'Destination Port Unreachable' [uint32]11006 = 'No Resources' [uint32]11007 = 'Bad Option' [uint32]11008 = 'Hardware Error' [uint32]11009 = 'Packet Too Big' [uint32]11010 = 'Request Timed Out' [uint32]11011 = 'Bad Request' [uint32]11012 = 'Bad Route' [uint32]11013 = 'TimeToLive Expired Transit' [uint32]11014 = 'TimeToLive Expired Reassembly' [uint32]11015 = 'Parameter Problem' [uint32]11016 = 'Source Quench' [uint32]11017 = 'Option Too Big' [uint32]11018 = 'Bad Destination' [uint32]11032 = 'Negotiating IPSEC' [uint32]11050 = 'General Failure' } Test-Connection -ComputerName $IPList -BufferSize 4 -Count 1 -AsJob Get-Job | Wait-Job | Receive-Job | ft Address,IPV4Address,IPV6Address,Buffersize,ResponseTime,@{n="Status";e={$StatusCodes[$_.statuscode]}}

使用状态码的缺点是,您需要翻译状态码。

Address        IPV4Address    IPV6Address Buffersize ResponseTime Status           
-------        -----------    ----------- ---------- ------------ ------           
172.217.161.15 172.217.161.15                      4          381 Success          
192.168.254.1                                      4              Request Timed Out

这给出了以下输出

Uncaught TypeError: Cannot read property 'length' of undefined at Object.addItem (app.js:41) at HTMLButtonElement.ctrlAddItem  

我很高兴这不会给您错误消息,但是您可以检查每个请求的状态,并使用它们来捕获错误以完成业务逻辑。

参考

IcmpSendEcho2 fails with fails with WSA_QOS_ADMISSION_FAILURE and ERROR_NOACCESS

https://docs.microsoft.com/en-gb/windows/desktop/api/ipexport/ns-ipexport-icmp_echo_reply

Powershell - Test-Connection failed due to lack of resources

答案 1 :(得分:1)

我没有特定的解决方案,但这是造成您问题的原因:

-AsJob参数创建一个WMI作业,而Start-Job参数创建一个CIM作业。

每个WMI作业都有自己的实例,而CIM作业在您当前的Powershell实例中运行。因此,WMI作业不需要花费额外的时间来使用当前会话来创建和销毁实例,这可能会非常昂贵。

一般而言,WMI作业与Powershell有点分离。他们似乎没有要复制的“主机” shell。这就是Powershell的双重性可能会使您感到困惑的地方。

不幸的是,在这种情况下,这意味着您完全依靠Test-Connection cmdlet来实现Powershell的事件处理程序,而事实并非如此,因为作业状态始终记录为“已完成”。通过简单地将其自身的shell转储到输出流中,您将不再能够依靠CIM作业带来的“兼容性”。

Start-Job -ScriptBlock {Write-Host "This is not real output."} | Wait-Job | Receive-Job
PS> This is not real output.

因此,在您的情况下,如果必须使用-AsJob,则最好的办法就是监视$error。 (据我所知。)