4

В 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 ответа4

3

Вы можете использовать это для проверки соединения - взято из репозитория кода PowerShell (автор 'BSonPosh'):

"Test-Port создает TCP-соединение с указанным портом. По умолчанию он подключается к порту 135 с таймаутом 3 сек. "

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){Write-Host "Connection Timeout"}
    Return $false
}
else
{
    # Close the connection and report the error if there is one
    $error.Clear()
    $tcpclient.EndConnect($iar) | out-Null
    if(!$?){if($verbose){write-host $error[0]};$failed = $true}
    $tcpclient.Close()
}

# Return $true if connection Establish else $False
if($failed){return $false}else{return $true}

Вы можете перейти на эту страницу репозитория для последующих действий (этот ответ уже слишком сложный)

2

Очень простой (время ожидания 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]@{hostname=$hostname;port=$port;open=$open}
}

testport

hostname  port  open
--------  ----  ----
yahoo.com   80  True
1

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

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 :)

0

Я искал супер быстрый способ пинговать многие 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}},
                    @{Name="Bytes"       ; Expression={$_.Buffer.Length}},
                    @{Name="Ttl"         ; Expression={$_.Options.Ttl}},
                    @{Name="ResponseTime"; Expression={$_.RoundtripTime}}
            }
            Unregister-Event $_.SourceIdentifier
            Remove-Event $_.SourceIdentifier
        }
    }
    if($Reply -eq $Null){
        Write-Verbose "Ping-IPrange : No ip address responded" -Verbose
    }

    return $Reply
}

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .