问题
I was setting up a monitoring script that would ping IPs and send an email when a packet fails. I decided to use Test-Connection
. Below is a sample code:
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
So the result I get is:
Source Destination IPV4Address IPV6Address Bytes Time(ms)
------ ----------- ----------- ----------- ----- --------
BLR-AA200906 172.217.161.15 4 55
BLR-AA200906 192.168.0.1 4
The 192 series IP is supposed to throw an error. You can see that the Time(ms)
column is empty.
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
If I do this, it will throw an error that I can easily catch
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
The Question
This brings me to my question. How can I receive/catch error messages thrown in Code1? The difference is I am using -AsJob
which is much more efficient than spinning up a job in a foreach
loop.
PS Version is 5.1
回答1:
It's important to differentiate that your code examples are doing different things, Code1 is spinning up a single job and running x number of test connections. Code2 is spinning up x number of jobs each testing 1 connection.
I'm not aware of a way to get the errors out of test-connection with -asjob, however a different approach would be to use the statuscode attribute. 11010
is the statuscode for Error due to lack of resources
which occurrs when test-connection doesn't receive a response from the host, aka Request Timed Out
.
The downside to using the statuscode, is that you need to translate the status codes.
$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]}}
This gives the following output
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
I appreciate this doesn't give you the error messages, but you can check the status of each request and use that to do the business logic you would have done by catching the errors.
References
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
回答2:
I don't have a particular solution, but this is the cause of your issue:
The -AsJob
parameter creates a WMI job, whereas Start-Job
creates a CIM job.
WMI jobs will each have their own instance, where as CIM jobs run in your current Powershell instance. Thus, WMI jobs do not take additional time to create and destroy instances using your current session, which can be very costly.
WMI jobs are a bit more detached from Powershell in general. They don't seem to have a "host" shell to transcribe to. This is where the duality of Powershell can get a bit confusing.
Unfortunately, in this case, that means you completely rely on the Test-Connection
cmdlet implementing Powershell's event handlers, and it appears that is not the case, since job states always record as 'Completed'. You are no longer able to fall back to the "compatibility" that CIM jobs bring by simply dumping their own shell to the output stream.
Start-Job -ScriptBlock {Write-Host "This is not real output."} | Wait-Job | Receive-Job
PS> This is not real output.
Thus, in your case, if you must use -AsJob
, the best you can do is monitor $error
. (As far as I can tell.)
来源:https://stackoverflow.com/questions/51542721/how-to-receive-errors-in-test-connection-with-asjob-switch