Teste portas de rede mais rapidamente com o PowerShell

4

No Windows 8.1, o cmdlet Test-NetConnection é útil para verificar o estado de uma porta de rede em um sistema remoto. No entanto, pode ser desnecessariamente lento às vezes. Gostaria de saber se há algumas opções que eu poderia ajustar ou um comando alternativo do PowerShell que eu poderia usar para tornar esse processo mais rápido.

Test-NetConnection pode levar cerca de 10 segundos para retornar resultados se um sistema remoto não estiver respondendo. Sempre que uma porta é especificada, ela executa dois testes de conexão que demoram cerca de 5 segundos cada para o tempo limite. O primeiro teste é uma verificação básica de eco ICMP. Isso esgotará o tempo limite se o sistema estiver off-line ou se (ou qualquer infraestrutura interveniente) estiver configurada para bloquear ou não responder às solicitações de eco ICMP. O segundo teste é a verificação real em relação à porta especificada. Isso esgotará o tempo limite se o sistema estiver off-line ou se houver um firewall ao longo do caminho que está bloqueando a porta.

No meu caso de uso atual, o sistema remoto está a apenas dois saltos em uma conexão Gigabit Ethernet confiável. Assim, um tempo limite de cinco segundos para qualquer solicitação é bastante excessivo - eu provavelmente ainda poderia obter resultados confiáveis com um tempo limite de 30 ms ou menos! Além disso, o sistema é conhecido por não responder ao eco do ICMP, embora possa estar online e ter todos os outros serviços disponíveis. Por isso, seria ótimo se eu pudesse passar sem o teste de eco ICMP completamente e reduzir o tempo limite para o teste de conexão TCP, a fim de acelerar meus scripts que usam Test-NetConnection para essa finalidade.

O Test-NetConnection tem opções para alterar esses comportamentos? (Eu li o arquivo de ajuda detalhado, e a resposta parece não ser - mas eu ficaria feliz em saber que há algo que eu perdi.) Ou há outra maneira de usar o PowerShell para executar as mesmas verificações, mas mais rápido?

Por vários motivos, prefiro manter meus scripts limitados a usar a funcionalidade incorporada ao sistema operacional sempre que possível. Presuma que o ambiente seja uma versão recente do Windows 8.1, com todas as Atualizações do Windows apropriadas aplicadas, e ferramentas de terceiros não são uma opção.

    
por Iszi 01.09.2014 / 04:33

4 respostas

3

Você pode usar isso para testar a conexão - Extraído do Código do PowerShell Repositório (autor 'BSonPosh') :

"Test-Port cria uma conexão TCP para a porta especificada. Por padrão, ele se conecta à porta 135 com um tempo limite de 3 segundos."

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}

Você pode ir para a página do repositório para acompanhamento (esta resposta já é muito de um trabalho de cópia)

    
por 24.09.2014 / 16:23
2

Muito básico (tempo limite de 100 ms):

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
    
por 31.05.2017 / 16:44
1

Um caminho ainda mais rápido poderia ser:

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

O resultado seria:

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

O valor interessting é "Conectado"

edit: mais um motivo: Test-NetConnection só funciona a partir do Powershell v5 (se bem me lembro), enquanto esta solução funciona da v2:)

    
por 30.05.2017 / 15:05
0

Eu estava procurando por uma maneira super rápida de pingar muitos IPs e tropeçar nessa questão (entre outros).

Por fim, encontrei um script que era fácil de integrar ao que eu queria fazer. O cara chama de Fast Ping Sweep Asynchronous .

Mesmo sendo um Power Shell n00b, consegui canalizar sua saída e modificar sua saída para incluir apenas o que eu queria. Eu me deparei com outros scripts, mas não consegui decifrar seus scripts para modificá-los para os meus propósitos.

Não sei qual versão do Power Shell é necessária, mas funciona na v4 e na v5.

I have seen most of the Powershell IP scanner, ping sweeping scripts but none of them uses the PingASync method.The "problem" with synchronous scripts is that they have to wait until a node replies or times out before continuing to the next address.Using this approach may take s

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
}
    
por 29.07.2017 / 15:50