Powershell - 由于资源不足,Test-Connection 失败

26

测试连接间歇性失败,提示资源不足错误:

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

因此,在需要在循环中测试计算机列表时,它并不可靠且几乎没有用。是否有修复、替代方案或解决方法可以使此功能可靠?

这是我目前的解决方案,但仍然不够可靠(有时它们仍然会连续失败5次),而且由于所有延迟和重试,它需要很长时间。

$Servers = Import-CSV -Path C:\Temp\Servers.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}
}

一般的ping(ping.exe)每次都有效,因此如果有一种好的方法可以用powershell解析它(主机是正常的还是宕机了,哪个IP地址正在响应),那似乎是最理想的解决方案,但我只需要能够工作的东西,所以我愿意接受任何建议。


嗯,看起来相当奇怪,为了解决这个问题,你可以实现“do-while”循环,但我建议你解决根本原因。比如,你尝试过什么来修复它?至少执行/sfc scannow命令吗?还是升级到PS5? - 4c74356b41
1
以前确实见过这种情况,但从未能找到解决方法,尽管我记得重新启动通常可以解决它(可能我记错了,已经过去一年了)。另外,你正在运行哪个版本的PS?我似乎记得这个问题只影响PSv2(同样可能记错了)。 - Mike Garuccio
1
使用-Quiet-ErrorAction SilentlyContinue或两者都使用如何?这可能是由于远程主机上的WMI故障引起的。而-Count 1并不总是可靠的。我的常规代码:if(Test-Connection $host -Quiet -Count 2 -EA 0) { #... },非常好用。 - sodawillow
我经常使用Windows 10上的Powershell 5,但在2012 R2上的Powershell 4上也会出现这种情况。我没有对其他版本进行广泛测试。我可以默默地忽略这些错误,但这些错误发生在已启动和未启动的主机上,因此无论如何结果都不准确。重新启动Powershell和计算机并不能解决问题(或者不能长期解决),也不是可行的选择。 - cscracker
6个回答

20
在较新版本的PowerShell中,Test-Connection命令的-Quiet参数似乎总是返回TrueFalse。在旧版本中似乎无法保持一致性,但可能是我现在做了某些不同的事情或他们已经改进了它。
$Ping = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet

我最近没有在网络不可用的情况下测试它。


旧回答:

Test-Connection 在 DNS 无法响应地址或网络不可用时表现不佳。如果该命令决定根本无法发送 ping,它会以难以捕获或忽略的不良方式出现错误。只有在您可以保证 DNS 将名称解析为地址并且网络始终存在时,Test-Connection 才有用。

我倾向于使用 CIM Pings(Powershell v3+):

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

或 WMI ping(PowerShell v1 或 v2):

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

两者基本上是相同的,但返回的格式略有不同。请注意,Get-WmiObject在Powershell v6中不可用,因为Get-CimInstance被设计为取代它。

这里的主要缺点是您必须自己解决状态代码:

$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];

此外,我也使用了像@BenH描述的 .Net Ping 这样的工具,它会为你做很多工作。但是我曾经停止使用它们而改用 WMI 和 CIM,但我现在无法记起来那个原因是什么。


1
这可能是因为.NET的ping命令不返回详细错误信息,似乎大多数情况下都是Success或TimedOut,但我还没有用不稳定的网络进行测试,以查看其是否返回其他错误代码。 - dragon788
@dragon788 是的,大多数这些网络状态很难轻易地重新创建。 - Bacon Bits
1
Get-WmiObject 版本不支持 IPv6 地址。根据 Microsoft 的说法,自 Vista 以来,WMI 支持 IPv6。然而,使用 IP6 地址会产生一个错误,其中 WMI 抱怨无效的 : 字符。Get-CimInstance 对于 IPv4 和 IPv6 都能正常工作。 - Brian H.
我喜欢使用 WMI Ping。 - js2010

14

我更倾向于使用.Net Ping类而不是Test-Connection

$Timeout = 100
$Ping = New-Object System.Net.NetworkInformation.Ping
$Response = $Ping.Send($Name,$Timeout)
$Response.Status
请注意,如果您需要设置TTL/分段,Send方法可以接受其他参数。同时,超时是以毫秒为单位计算的,仅使用$name进行超时设置时,默认超时时间为5秒,这通常太长了。

12

Windows IP Helper 定义了 IP_REQ_TIMED_OUT 错误的值为 11010,与 Windows 系统错误 WSA_QOS_ADMISSION_FAILURE 11010 “由于资源不足而导致的错误” 相同。因此,在疑问情况下实际接收到的很可能是超时错误,并被错误地解释为“资源不足”。


1
这比 DNS 问题更有意义,特别是在针对成功和失败的 IPv4 地址进行测试时,如 8.8.8.8 和 7.7.7.7 ;) - danno

1

在编程中,当我(在5.x中)在test-connection中包括-computername时,就会出现这个错误。 去掉它就可以了。另外关于使用ping与test-connection,ICMP在Windows防火墙中默认是被阻止的,而test-connection则执行win32_pingstatus命令的等价操作。WMI不会被默认阻止。但是,如果系统上的WMI存储库不健康(或被防火墙阻止),那么它肯定会失败。


这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - Draken

0

使用test-connection命令时,powershell v7不会出现这个问题。


0

我要作弊,使用PowerShell 7。微软总是无法ping通。

test-connection -count 1 yahoo.com,microsoft.com | select destination,status

Destination     Status
-----------     ------
yahoo.com      Success
microsoft.com TimedOut

或者多线程:

echo yahoo.com microsoft.com | % -parallel { test-connection -count 1 $_ } | 
  select destination,status

Destination     Status
-----------     ------
yahoo.com      Success
microsoft.com TimedOut

,'microsoft.com' * 10 | % -parallel { test-connection -count 1 $_ } | 
  select destination,status

Destination     Status
-----------     ------
microsoft.com TimedOut
microsoft.com TimedOut
microsoft.com TimedOut
microsoft.com TimedOut
microsoft.com TimedOut
microsoft.com TimedOut
microsoft.com TimedOut
microsoft.com TimedOut
microsoft.com TimedOut
microsoft.com TimedOut


# one time takes like 4 seconds
measure-command { ,'microsoft.com' * 10 | % -parallel { test-connection -count 1 $_ } | 
  select destination,status } | % seconds

9

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接