8 votes

Tester les ports réseau plus rapidement avec PowerShell

Dans Windows 8.1, la commande Test-NetConnection est utile pour vérifier l'état d'un port réseau sur un système distant. Cependant, il peut parfois être inutilement lent. Je voudrais savoir s'il existe des options que je pourrais ajuster, ou une autre commande PowerShell que je pourrais utiliser, pour accélérer ce processus.

Test-NetConnection peut prendre environ 10 secondes pour renvoyer des résultats si un système distant ne répond pas. Chaque fois qu'un port est spécifié, il exécute deux tests de connexion qui prennent environ 5 secondes chacun pour expirer. Le premier test est une vérification de base de l'écho ICMP. Cela expirera si le système est hors ligne, ou si celui-ci (ou toute infrastructure intermédiaire) est configuré pour bloquer ou ne pas répondre aux demandes d'écho ICMP. Le deuxième test est la vérification réelle du port spécifié. Cela expirera si le système est hors ligne, ou s'il y a un pare-feu sur le chemin qui bloque le port.

Dans mon cas d'utilisation actuel, le système distant n'est qu'à deux sauts sur une connexion Ethernet Gigabit fiable. Ainsi, une attente de cinq secondes pour toute demande est assez excessive - je pourrais probablement obtenir des résultats fiables avec une attente de 30 ms ou moins ! De plus, le système est connu pour ne pas répondre à l'écho ICMP même s'il est en ligne et que tous les autres services sont disponibles. Il serait donc intéressant de pouvoir se passer complètement du test d'écho ICMP et de réduire le délai d'attente pour le test de connexion TCP, afin d'accélérer mes scripts qui utilisent Test-NetConnection à cette fin.

Test-NetConnection dispose-t-il d'options pour modifier ces comportements ? (J'ai lu le fichier d'aide détaillé, et la réponse semble être non - mais je serais heureux d'apprendre s'il y a quelque chose que j'ai manqué.) Ou existe-t-il un autre moyen d'utiliser PowerShell pour effectuer les mêmes vérifications, mais plus rapidement ?

Pour diverses raisons, je préfère limiter mes scripts à utiliser des fonctionnalités intégrées au système d'exploitation autant que possible. Supposons que l'environnement est une installation fraîche de Windows 8.1, avec toutes les mises à jour appropriées de Windows appliquées, et que les outils tiers ne sont pas une option.

9voto

Jackson Points 6654

Très basique (délai d'attente 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

5voto

Jan Doggen Points 3901

Vous pouvez utiliser cela pour tester la connexion - Extrait du dépôt de code PowerShell (auteur 'BSonPosh'):

"Test-Port crée une connexion TCP au port spécifié. Par défaut, il se connecte au port 135 avec un délai d'attente de 3 secondes."

Param([string]$srv,$port=135,$timeout=3000,[switch]$verbose)

# Test-Port.ps1
# Effectue une connexion TCP sur le port spécifié (135 par défaut)

$ErrorActionPreference = "SilentlyContinue"

# Créer un client TCP
$tcpclient = new-Object system.Net.Sockets.TcpClient

# Indiquer au client TCP de se connecter à la machine sur le port
$iar = $tcpclient.BeginConnect($srv,$port,$null,$null)

# Définir le temps d'attente
$wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)

# Vérifier si la connexion est terminée
if(!$wait)
{
    # Fermer la connexion et signaler le dépassement du délai
    $tcpclient.Close()
    if($verbose){Write-Host "Délai de connexion dépassé"}
    Return $false
}
else
{
    # Fermer la connexion et signaler l'erreur s'il y en a une
    $error.Clear()
    $tcpclient.EndConnect($iar) | out-Null
    if(!$?){if($verbose){write-host $error[0]};$failed = $true}
    $tcpclient.Close()
}

# Retourner $true si la connexion est établie sinon $false
if($failed){return $false}else{return $true}

Vous pouvez consulter cette page du dépôt pour les suivis (cette réponse est déjà trop un copier-coller)

2voto

laurent Points 21

Une façon encore plus rapide pourrait être :

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

Le résultat serait :

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

La valeur intéressante est "Connected"

edit : une raison de plus : Test-NetConnection ne fonctionne que depuis Powershell v5 (si je me souviens bien), alors que cette solution fonctionne depuis v2 :)

2voto

Hashbrown Points 2148

En prenant la réponse de @Jan, je l'ai rendue moins encombrée et maintenant elle fonctionne pour moi dans les tâches lancées.
C'est bien de jeter des exceptions et de ne pas compter sur $error / les utilisateurs d'API utilisant des choses non-standard "verbeuses" aussi (obtenir .Connected semble provoquer l'apparition de SocketException ce qui est propre).

        Function TestTCP { Param($address, $port, $timeout=2000)
            $socket=New-Object System.Net.Sockets.TcpClient
            try {
                $result=$socket.BeginConnect($address, $port, $NULL, $NULL)
                if (!$result.AsyncWaitHandle.WaitOne($timeout, $False)) {
                    throw [System.Exception]::new('Délai de connexion dépassé')
                }
                $socket.EndConnect($result) | Out-Null
                $socket.Connected
            }
            finally {
                $socket.Close()
            }
        }

0voto

James Curtis Points 1

Voici mon entrée, merci pour le code qui m'a lancé. Tout le code est documenté en ligne

PS> aide Test-PortScan -exemples

function Test-PortScan
{
<#
    .SYNOPSIS
        Teste pour voir si un port ou une plage est ouverte

    .DESCRIPTION
        Une description détaillée de la fonction Test-PortScan.

    .PARAMETER Devices
        IP ou nom d'hôte des appareils à tester. Il prendra la valeur de la pipeline afin de pouvoir tester plusieurs appareils en même temps.

    .PARAMETER StartPort
        Numéro de port de départ à tester. Par défaut, il est défini sur 1.

    .PARAMETER EndPort
        Dernier port d'une plage à balayer. Par défaut, il est le même que le port de départ, donc si vous voulez entrer seulement 1 port, vous n'avez pas à définir cette variable.

    .PARAMETER Timeout
        Durée du délai pour tester la connexion en millisecondes. Par défaut, il est de 100 millisecondes.

    .EXAMPLE
        Test-PortScan -devices 192.168.1.1 -StartPort 20 -EndPort 82
        Teste l'appareil à 192.168.1.1 sur les ports 20 - 82

    .EXAMPLE
        Test-PortScan -Devices 192.168.1.1 -StartPort 80
            Teste l'appareil à 192.168.1.1 pour le port 80 (également Test-PortScan 192.168.1.1 80)

    .EXAMPLE
        '192.168.1.1','192.168.1.2','122.168.1.3' | % {Test-PortScan -Devices $_ StartPort 22 25}
        Teste chacune de ces adresses IP sur les ports 22 - 25

    .NOTES
        # Code original trouvé ici : https://superuser.com/questions/805621/test-network-ports-faster-with-powershell
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true,
                   Position = 0,
                   HelpMessage = 'Vous devez fournir au moins un nom de périphérique ou une IP')]
        [Alias('Nom')]
        [string]$Devices,
        [Parameter(Position = 1)]
        [int]$StartPort = 1,
        [Parameter(Position = 2)]
        [int]$EndPort = $StartPort,
        [Parameter(Position = 3)]
        [int]$Timeout = 100
    )

    BEGIN
    {
        $PSObject = @()
        $Output = @()
    }
    PROCESS
    {
        foreach ($Device in $Devices)
        {
            Write-Verbose "Pas encore dans la boucle port"
            $Port = $StartPort
            do
            {
                #($Port = $StartPort; $Port -gt $EndPort; $Port++)              
                Write-Verbose "Arrivé à la boucle de port"
                $requestCallback = $state = $null
                $client = New-Object System.Net.Sockets.TcpClient
                $beginConnect = $client.BeginConnect($Device, $Port, $requestCallback, $state)
                Start-Sleep -Milliseconds $Timeout
                if ($client.Connected) { $Open = $true }
                else { $Open = $false }
                $client.Close()
                [pscustomobject]@{
                    'Ordinateur' = $Device
                    'Port'     = $Port
                    'Ouvert'     = $Open
                }
                $Port += 1
            }
            until ($Port -gt $EndPort)
        }

    }
    END
    {

    }
}

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X