我正在设置一个监视脚本,该脚本将在数据包失败时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
答案 0 :(得分:1)
重要的是要区分您的代码示例在做不同的事情,Code1正在完成一项工作并运行了x个测试连接。 Code2正在加速x每个测试1个连接的作业数。
我不知道使用-asjob从测试连接中消除错误的方法,但是另一种方法是使用statuscode属性。 11010
是Error 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
。 (据我所知。)