Inhalt

UDP Verbindung mit PowerShell prüfen

Bei der Analyse von Netzwerkproblemen ist ein einfacher ICMP Ping nie ausreichend um zu verifizieren, ob die Verbindung zwischen zwei Geräten funktioniert. Im Normalfall wird eine TCP Verbindung zu einer Serverkomponente benötigt und PowerShell bringt mit Test-NetConnection ein entsprechendes cmdlet mit.

/udp-verbindung-mit-powershell-pruefen/images/Test-NetworkConnection.png

Von Haus aus unterstützt Test-NetConnection jedoch ausschließlich TCP Verbindungen und testet außerdem jedes Mal noch einen ICMP Ping.

Und was ist mit UDP?

Für die Analyse von stateless UDP Paketen gibt es kein Boardmittel, weshalb ich die folgenden zwei Funktionen geschrieben habe.

  • Start-UDPServer übernimmt die Rolle des Servers und kann nur eingsetzt werden wenn der eigentliche Dienst nicht läuft.
  • Test-NetConnectionUDP sendet das aktuelle Datum inkl. Uhrzeit an den Server.

/udp-verbindung-mit-powershell-pruefen/images/Test-NetworkConnectionUDP.gif

Start-UDPServer

Die Funktion kennt nur einen Parameter und das ist -Port. Sobald sie gestartet wurde werden alle eingehenden UDP Pakete angenommen und zusammen mit der lokalen Uhrzeit, der gesendeten Uhrzeit sowie der Quell IP-Adresse und dem Quell Port angezeigt.

function Start-UDPServer {
    [CmdletBinding()]
    param (
        # Parameter help description
        [Parameter(Mandatory = $false)]
        $Port = 10000
    )
    
    # Create a endpoint that represents the remote host from which the data was sent.
    $RemoteComputer = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0)
    Write-Host "Server is waiting for connections - $($UdpObject.Client.LocalEndPoint)"
    Write-Host "Stop with CRTL + C"

    # Loop de Loop
    do {
        # Create a UDP listender on Port $Port
        $UdpObject = New-Object System.Net.Sockets.UdpClient($Port)
        # Return the UDP datagram that was sent by the remote host
        $ReceiveBytes = $UdpObject.Receive([ref]$RemoteComputer)
        # Close UDP connection
        $UdpObject.Close()
        # Convert received UDP datagram from Bytes to String
        $ASCIIEncoding = New-Object System.Text.ASCIIEncoding
        [string]$ReturnString = $ASCIIEncoding.GetString($ReceiveBytes)

        # Output information
        [PSCustomObject]@{
            LocalDateTime = $(Get-Date -UFormat "%Y-%m-%d %T")
            SourceIP      = $RemoteComputer.address.ToString()
            SourcePort    = $RemoteComputer.Port.ToString()
            Payload       = $ReturnString
        }
    } while (1)
}

Test-NetConnectionUDP

Auf dem Client müssen mindestens der Ziel -Port und Server -ComputerName angegeben werden. Mittels -SourcePort kann auch noch der absendende Port beeinflusst werden, was beim Test von Firewallregeln hilft.

function Test-NetConnectionUDP {
    [CmdletBinding()]
    param (
        # Desit
        [Parameter(Mandatory = $true)]
        [int32]$Port,

        # Parameter help description
        [Parameter(Mandatory = $true)]
        [string]$ComputerName,

        # Parameter help description
        [Parameter(Mandatory = $false)]
        [int32]$SourcePort = 50000
    )

    begin {
        # Create a UDP client object
        $UdpObject = New-Object system.Net.Sockets.Udpclient($SourcePort)
        # Define connect parameters
        $UdpObject.Connect($ComputerName, $Port)
    }

    process {
        # Convert current time string to byte array
        $ASCIIEncoding = New-Object System.Text.ASCIIEncoding
        $Bytes = $ASCIIEncoding.GetBytes("$(Get-Date -UFormat "%Y-%m-%d %T")")
        # Send data to server
        [void]$UdpObject.Send($Bytes, $Bytes.length)
    }

    end {
        # Cleanup
        $UdpObject.Close()
    }
}

Known Issues

  • Das erste Paket wird nicht sofort angezeigt, sondern erst mit Erhalt des zweiten Pakets.
  • Der Server muss nachdem er mittels CTRL+C beendet wurde noch ein Paket beenden und die Schleife zu verlassen.
  • Die genutzten Ports dürfen nicht durch eine andere Applikation genutzt werden.

Update 11.02.2021: Start-TCPServer

Während der aktuellen Hamburg PowerShell User Group haben wir einen TCP Listener gebaut der vom nativen Test-NetConnection angesprochen werden kann.

function Start-TCPServer {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        $Port = 10000
    )
    do {
        # Create a TCP listender on Port $Port
        $TcpObject = New-Object System.Net.Sockets.TcpListener($port)
        # Start TCP listener
        $ReceiveBytes = $TcpObject.Start()
        # Accept TCP client connection
        $ReceiveBytes = $TcpObject.AcceptTcpClient()
        # Stop TCP Client listener
        $TcpObject.Stop()
        # Output information about remote client
        $ReceiveBytes.Client.RemoteEndPoint
    }  while (1)
}