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



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

Code1

$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)列为空。

Code2

$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

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

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

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

WMI作业通常与Powershell有点分离。它们似乎没有一个"宿主"外壳可以转录。这就是Powershell的二元性可能会变得有点混乱的地方。

不幸的是,在这种情况下,这意味着您完全依赖于实现Powershell的事件处理程序的Test-Connectioncmdlet,但事实并非如此,因为作业状态总是记录为"Completed"。您再也无法通过简单地将CIM作业自己的shell转储到输出流来恢复CIM作业所带来的"兼容性"。

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

因此,在您的情况下,如果必须使用-AsJob,那么您能做的最好的事情就是监视$error。(据我所知。(

重要的是要区分您的代码示例正在做不同的事情,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

我很感激这不会给你错误消息,但你可以检查每个请求的状态,并用它来执行你本可以通过捕捉错误来完成的业务逻辑。

参考

IcmpSendEcho2失败,WSA_QOS_ADMISSION_FAILURE和ERROR_NOACCESS 失败

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

Powershell-由于缺乏资源,测试连接失败

最新更新