Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

ping - Powershell - Test-Connection failed due to lack of resources

Test-connection intermittently fails with a lack of resources error:

test-connection : Testing connection to computer 'SOMESERVER' failed: Error due to lack of resources
At line:1 char:45
+ ... ($server in $ServersNonProd.Name) { test-connection $server -Count 1}
+                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (SOMESERVER:String) [Test-Connection], PingException
    + FullyQualifiedErrorId : TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand

As a result, it's not reliable and fairly useless when you need to test a list of computers in a loop. Is there a fix, alternative, or workaround to get this functionality reliably?

This is my current solution, but it's still not sufficiently reliable (sometimes they still fail 5 times in a row) and it takes forever because of all the delays and retries.

$Servers = Import-CSV -Path C:TempServers.csv

$result = foreach ($Name in $Servers.FQDN) {
    $IP = $null
    if ( Resolve-DNSName $Name -ErrorAction SilentlyContinue ) {
        $IP = (Test-Connection -Count 1 -ComputerName $Name -ErrorAction SilentlyContinue).IPv4Address
        if ( $IP -eq $null ) {
            Start-Sleep -Milliseconds 100
            $IP = (Test-Connection -Count 1 -ComputerName $Name -ErrorAction SilentlyContinue).IPv4Address
        }
        if ( $IP -eq $null ) {
            Start-Sleep -Milliseconds 200
            $IP = (Test-Connection -Count 1 -ComputerName $Name -ErrorAction SilentlyContinue).IPv4Address
        }
        if ( $IP -eq $null ) {
            Start-Sleep -Milliseconds 300
            $IP = (Test-Connection -Count 1 -ComputerName $Name -ErrorAction SilentlyContinue).IPv4Address
        }
        if ( $IP -eq $null ) {
            Start-Sleep -Milliseconds 400
            $IP = (Test-Connection -Count 1 -ComputerName $Name -ErrorAction SilentlyContinue).IPv4Address
        }
    }
    new-object psobject -Property @{FQDN = $Name; "IP Address" = $IP}
}

A normal ping (ping.exe) works every time, so if there's a good way to parse that with powershell (host up or down, what IP is responding), that seems like the ideal solution, but I just need something that works, so I'm open to ideas.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In newer versions of PowerShell, the -Quiet parameter on Test-Connection does seem to always return either True or False. It didn't seem to work consistently on older versions, but either I'm doing something differently now or they've improved it:

$Ping = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet

I haven't tested it recently when the network is simply unavailable, however.


Older answer:

Test-Connection doesn't respond well when DNS doesn't respond with an address or when the network is unavailable. That is, if the cmdlet decides it can't send the ping at all, it errors in unpleasant ways that are difficult to trap or ignore. Test-Connection is only useful, then, when you can guarantee that DNS will resolve the name to an address, and that the network will always be present.

I tend to use CIM Pings (Powershell v3+):

$Ping2 = Get-CimInstance -ClassName Win32_PingStatus -Filter "Address='$ComputerName' AND Timeout=1000";

Or WMI pings (Powershell v1 or v2):

$Ping = Get-WmiObject -Class Win32_PingStatus -Filter "Address='$ComputerName' AND Timeout=1000";

Either of which are basically the same, but return slightly different formats for things. Note that Get-WmiObject is not available at all beginning in Powershell v6 because Get-CimInstance was designed to supersede it.

The main disadvantage here is that you have to resolve the status code yourself:

$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'
    };
$StatusCodes[$Ping.StatusCode];
$StatusCodes[$Ping2.StatusCode];

Alternately, I've used .Net Pings like @BenH described, too, which does a lot of that work for you. There was a reason I stopped using them in favor of WMI and CIM, but I can no longer remember what that reason was.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...