Powershell - 由于缺乏资源,测试连接失败
Powershell - Test-Connection failed due to lack of resources
测试连接因缺少资源错误而间歇性失败:
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 正在响应),这似乎是理想的解决方案,但是我只需要有用的东西,所以我愿意接受想法。
我偏向于使用 .Net Ping class 而不是 Test-Connection
$Timeout = 100
$Ping = New-Object System.Net.NetworkInformation.Ping
$Response = $Ping.Send($Name,$Timeout)
$Response.Status
请注意,如果您需要设置 TTL/Fragmentation,Send 方法可以使用额外的参数。超时也以毫秒为单位,只有 $name 我认为超时是 5 秒,这通常太长了。
在较新版本的 PowerShell 中,Test-Connection
上的 -Quiet
参数似乎总是 return True
或 False
。它在旧版本上似乎无法始终如一地工作,但我现在正在做一些不同的事情,或者他们已经改进了它:
$Ping = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet
然而,当网络根本不可用时,我最近没有测试它。
较早的回答:
当 DNS 未响应地址或网络不可用时,Test-Connection
响应不佳。也就是说,如果 cmdlet 决定它根本无法发送 ping,它就会以难以捕捉或忽略的令人不快的方式出错。 Test-Connection
仅在您可以保证 DNS 将名称解析为地址并且网络始终存在时才有用。
我倾向于使用 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";
两者基本相同,但return格式略有不同。请注意,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 Pings,它可以为您完成很多工作。我停止使用它们以支持 WMI 和 CIM 是有原因的,但我不再记得那个原因是什么了。
Windows IP Helper 将 IP_REQ_TIMED_OUT 错误定义为值 11010,这与 Windows 系统错误 WSA_QOS_ADMISSION_FAILURE 11010 'Error due to lack of resources.' 相同
所以很可能在被质疑的情况下实际收到的是超时错误,只是被误解为 'lack of resources'.
powershell v7 在使用测试连接时不会遇到这个问题
我要作弊用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
我在测试连接中包含 -computername 时(无论如何在 5.x 中)看到此错误。
删除它并且它有效。关于使用 ping 与 test-connection 的另一件事,ICMP 默认情况下被 windows 防火墙阻止,其中 test-connection 与 win32_pingstatus 命令等效。默认情况下不阻止 WMI。但是,如果系统上的 WMI 存储库不健康(或被 fw 阻止),它当然会失败。
测试连接因缺少资源错误而间歇性失败:
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 正在响应),这似乎是理想的解决方案,但是我只需要有用的东西,所以我愿意接受想法。
我偏向于使用 .Net Ping class 而不是 Test-Connection
$Timeout = 100
$Ping = New-Object System.Net.NetworkInformation.Ping
$Response = $Ping.Send($Name,$Timeout)
$Response.Status
请注意,如果您需要设置 TTL/Fragmentation,Send 方法可以使用额外的参数。超时也以毫秒为单位,只有 $name 我认为超时是 5 秒,这通常太长了。
在较新版本的 PowerShell 中,Test-Connection
上的 -Quiet
参数似乎总是 return True
或 False
。它在旧版本上似乎无法始终如一地工作,但我现在正在做一些不同的事情,或者他们已经改进了它:
$Ping = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet
然而,当网络根本不可用时,我最近没有测试它。
较早的回答:
当 DNS 未响应地址或网络不可用时,Test-Connection
响应不佳。也就是说,如果 cmdlet 决定它根本无法发送 ping,它就会以难以捕捉或忽略的令人不快的方式出错。 Test-Connection
仅在您可以保证 DNS 将名称解析为地址并且网络始终存在时才有用。
我倾向于使用 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";
两者基本相同,但return格式略有不同。请注意,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 Pings,它可以为您完成很多工作。我停止使用它们以支持 WMI 和 CIM 是有原因的,但我不再记得那个原因是什么了。
Windows IP Helper 将 IP_REQ_TIMED_OUT 错误定义为值 11010,这与 Windows 系统错误 WSA_QOS_ADMISSION_FAILURE 11010 'Error due to lack of resources.' 相同 所以很可能在被质疑的情况下实际收到的是超时错误,只是被误解为 'lack of resources'.
powershell v7 在使用测试连接时不会遇到这个问题
我要作弊用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
我在测试连接中包含 -computername 时(无论如何在 5.x 中)看到此错误。 删除它并且它有效。关于使用 ping 与 test-connection 的另一件事,ICMP 默认情况下被 windows 防火墙阻止,其中 test-connection 与 win32_pingstatus 命令等效。默认情况下不阻止 WMI。但是,如果系统上的 WMI 存储库不健康(或被 fw 阻止),它当然会失败。