Тестируйте сетевые порты быстрее с PowerShell

13227
Iszi

В Windows 8.1 Test-NetConnectionкомандлет полезен для проверки состояния сетевого порта в удаленной системе. Однако иногда это может быть излишне медленным. Я хотел бы знать, есть ли варианты, которые я мог бы настроить, или альтернативная команда PowerShell, которую я мог бы использовать, чтобы ускорить этот процесс.

Test-NetConnectionвозврат результатов может занять около 10 секунд, если удаленная система не отвечает. Всякий раз, когда указан порт, он запускает два теста соединения, каждый из которых занимает около 5 секунд. Первый тест - это базовая проверка эхо-кода ICMP. Это приведет к превышению времени ожидания, если система находится в автономном режиме или если она (или любая промежуточная инфраструктура) настроена на блокировку или отсутствие ответа на эхо-запросы ICMP. Второй тест - это фактическая проверка указанного порта. Это приведет к истечению времени ожидания, если система отключена или если на пути, блокирующем порт, установлен брандмауэр.

В моем текущем случае использования удаленная система находится всего в двух шагах от надежного соединения Gigabit Ethernet. Таким образом, пятисекундный таймаут для любого запроса является чрезмерным - я, вероятно, мог бы получить надежные результаты с тайм-аутом 30 мс или меньше! Кроме того, известно, что система не реагирует на эхо-сигналы ICMP, хотя она может быть подключена к сети и иметь все другие доступные службы. Поэтому было бы здорово, если бы я мог полностью обойтись без эхо-теста ICMP и сократить время ожидания для теста TCP-соединения, чтобы ускорить выполнение моих сценариев, используемых Test-NetConnectionдля этой цели.

Есть ли Test-NetConnectionварианты, чтобы изменить эти поведения? (Я прочитал подробный файл справки, и ответ, похоже, нет - но я был бы рад, если бы мне сказали, что я что-то пропустил.) Или есть другой способ использовать PowerShell для выполнения тех же проверок, но быстрее?

По разным причинам я предпочитаю ограничивать использование сценариев функциональностью, встроенной в операционную систему, где это возможно. Предположим, что среда представляет собой свежую сборку Windows 8.1 со всеми применимыми обновлениями Windows, а сторонние инструменты недоступны.

4
Смежный вопрос: [Как проверить открытые порты с помощью powershell?] (Http://stackoverflow.com/q/19213830) Некоторые статьи, которые также могут быть полезны: [Powershell - Тест TCP-портов на удаленных серверах] (http: // noamwajnman.wordpress.com/2014/04/02/powershell-test-tcp-ports-on-remote-servers/), [Проверить наличие открытых портов TCP с помощью PowerShell] (http://www.powershelladmin.com/wiki/ Check_for_open_TCP_ports_using_PowerShell), [Тестирование портов TCP с возможным ответом заголовка] (http://learn-powershell.net/2014/04/18/testing-tcp-ports-with-a-possible-header-response/) and31415 9 лет назад 0

4 ответа на вопрос

3
Jan Doggen

You can use this to test the connection - Taken from the PowerShell Code Repository (author 'BSonPosh'):

"Test-Port creates a TCP connection to specified port. By default it connects to port 135 with a timeout of 3secs."

Param([string]$srv,$port=135,$timeout=3000,[switch]$verbose) # Test-Port.ps1 # Does a TCP connection on specified port (135 by default) $ErrorActionPreference = "SilentlyContinue" # Create TCP Client $tcpclient = new-Object system.Net.Sockets.TcpClient # Tell TCP Client to connect to machine on Port $iar = $tcpclient.BeginConnect($srv,$port,$null,$null) # Set the wait time $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false) # Check to see if the connection is done if(!$wait) { # Close the connection and report timeout $tcpclient.Close() if($verbose) Return $false } else { # Close the connection and report the error if there is one $error.Clear() $tcpclient.EndConnect($iar) | out-Null if(!$?);$failed = $true} $tcpclient.Close() } # Return $true if connection Establish else $False if($failed)else 

You can go to that repository page for follow-ups (this answer is already too much of a copy-job)

2
js2010

Очень простой (время ожидания 100 мс):

function testport ($hostname='yahoo.com',$port=80,$timeout=100) { $requestCallback = $state = $null $client = New-Object System.Net.Sockets.TcpClient $beginConnect = $client.BeginConnect($hostname,$port,$requestCallback,$state) Start-Sleep -milli $timeOut if ($client.Connected) { $open = $true } else { $open = $false } $client.Close() [pscustomobject]@ }  testport  hostname port open -------- ---- ---- yahoo.com 80 True 
1
laurent

Еще более быстрый способ может быть:

param($ip,$port) New-Object System.Net.Sockets.TCPClient -ArgumentList $ip, $port 

Результат будет:

Client : System.Net.Sockets.Socket Available : 0 Connected : True ExclusiveAddressUse : False ReceiveBufferSize : 65536 SendBufferSize : 65536 ReceiveTimeout : 0 SendTimeout : 0 LingerState : System.Net.Sockets.LingerOption NoDelay : False 

Интересная ценность "Связано"

редактирование: еще одна причина: Test-NetConnection работает только с Powershell v5 (если я правильно помню), в то время как это решение работает с v2 :)

Этот путь занимает гораздо больше времени, если хост недоступен, чем решение Яна. Mark Allison 6 лет назад 0
Работает на PS v4.0 тоже Janis Veinbergs 6 лет назад 0
0
YetAnotherRandomUser

Я искал супер быстрый способ пинговать многие IP-адреса и наткнулся на этот вопрос (среди прочих).

В конце концов я нашел скрипт, который легко интегрировать в то, что я хотел сделать. Парень называет это Fast Ping Sweep Asynchronous .

Даже будучи Power Shell n00b, я смог передать его вывод и затем изменить его, чтобы включить только то, что хотел. Я сталкивался с другими сценариями, но не мог расшифровать их сценарии, чтобы изменить их для моих целей.

Я не уверен, какая версия Power Shell для этого требуется, но она работает на v4 и v5.

Я видел большинство IP-сканеров Powershell, проверяющих широкие сценарии, но ни один из них не использует метод PingASync. «Проблема» с синхронными сценариями заключается в том, что им приходится ждать, пока узел не ответит, или время ожидания истекло, прежде чем перейти к следующему адресу. Использование этот подход может занять

function Global:Ping-IPRange { <# .SYNOPSIS Sends ICMP echo request packets to a range of IPv4 addresses between two given addresses.  .DESCRIPTION This function lets you sends ICMP echo request packets ("pings") to  a range of IPv4 addresses using an asynchronous method.  Therefore this technique is very fast but comes with a warning. Ping sweeping a large subnet or network with many swithes may result in  a peak of broadcast traffic. Use the -Interval parameter to adjust the time between each ping request. For example, an interval of 60 milliseconds is suitable for wireless networks. The RawOutput parameter switches the output to an unformated [System.Net.NetworkInformation.PingReply[]].  .INPUTS None You cannot pipe input to this funcion.  .OUTPUTS The function only returns output from successful pings.  Type: System.Net.NetworkInformation.PingReply  The RawOutput parameter switches the output to an unformated [System.Net.NetworkInformation.PingReply[]].  .NOTES Author : G.A.F.F. Jakobs Created : August 30, 2014 Version : 6  .EXAMPLE Ping-IPRange -StartAddress 192.168.1.1 -EndAddress 192.168.1.254 -Interval 20  IPAddress Bytes Ttl ResponseTime --------- ----- --- ------------ 192.168.1.41 32 64 371 192.168.1.57 32 128 0 192.168.1.64 32 128 1 192.168.1.63 32 64 88 192.168.1.254 32 64 0  In this example all the ip addresses between 192.168.1.1 and 192.168.1.254 are pinged using  a 20 millisecond interval between each request. All the addresses that reply the ping request are listed.  .LINK http://gallery.technet.microsoft.com/Fast-asynchronous-ping-IP-d0a5cf0e  #> [CmdletBinding(ConfirmImpact='Low')] Param( [parameter(Mandatory = $true, Position = 0)] [System.Net.IPAddress]$StartAddress, [parameter(Mandatory = $true, Position = 1)] [System.Net.IPAddress]$EndAddress, [int]$Interval = 30, [Switch]$RawOutput = $false )  $timeout = 2000  function New-Range ($start, $end) {  [byte[]]$BySt = $start.GetAddressBytes() [Array]::Reverse($BySt) [byte[]]$ByEn = $end.GetAddressBytes() [Array]::Reverse($ByEn) $i1 = [System.BitConverter]::ToUInt32($BySt,0) $i2 = [System.BitConverter]::ToUInt32($ByEn,0) for($x = $i1;$x -le $i2;$x++){ $ip = ([System.Net.IPAddress]$x).GetAddressBytes() [Array]::Reverse($ip) [System.Net.IPAddress]::Parse($($ip -join '.')) } }  $IPrange = New-Range $StartAddress $EndAddress  $IpTotal = $IPrange.Count  Get-Event -SourceIdentifier "ID-Ping*" | Remove-Event Get-EventSubscriber -SourceIdentifier "ID-Ping*" | Unregister-Event  $IPrange | foreach{  [string]$VarName = "Ping_" + $_.Address  New-Variable -Name $VarName -Value (New-Object System.Net.NetworkInformation.Ping)  Register-ObjectEvent -InputObject (Get-Variable $VarName -ValueOnly) -EventName PingCompleted -SourceIdentifier "ID-$VarName"  (Get-Variable $VarName -ValueOnly).SendAsync($_,$timeout,$VarName)  Remove-Variable $VarName  try{  $pending = (Get-Event -SourceIdentifier "ID-Ping*").Count  }catch [System.InvalidOperationException]{}  $index = [array]::indexof($IPrange,$_)  Write-Progress -Activity "Sending ping to" -Id 1 -status $_.IPAddressToString -PercentComplete (($index / $IpTotal) * 100)  Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($index - $pending) -PercentComplete (($index - $pending)/$IpTotal * 100)  Start-Sleep -Milliseconds $Interval }  Write-Progress -Activity "Done sending ping requests" -Id 1 -Status 'Waiting' -PercentComplete 100   While($pending -lt $IpTotal){  Wait-Event -SourceIdentifier "ID-Ping*" | Out-Null  Start-Sleep -Milliseconds 10  $pending = (Get-Event -SourceIdentifier "ID-Ping*").Count  Write-Progress -Activity "ICMP requests pending" -Id 2 -ParentId 1 -Status ($IpTotal - $pending) -PercentComplete (($IpTotal - $pending)/$IpTotal * 100) }  if($RawOutput){  $Reply = Get-Event -SourceIdentifier "ID-Ping*" | ForEach {  If($_.SourceEventArgs.Reply.Status -eq "Success"){ $_.SourceEventArgs.Reply } Unregister-Event $_.SourceIdentifier Remove-Event $_.SourceIdentifier }  }else{  $Reply = Get-Event -SourceIdentifier "ID-Ping*" | ForEach {  If($_.SourceEventArgs.Reply.Status -eq "Success"){ $_.SourceEventArgs.Reply | select @{ Name="IPAddress" ; Expression={$_.Address}}, @}, @}, @} } Unregister-Event $_.SourceIdentifier Remove-Event $_.SourceIdentifier } } if($Reply -eq $Null){ Write-Verbose "Ping-IPrange : No ip address responded" -Verbose }  return $Reply }