12
votes

I am trying to write a script to test and application using PowerShell. The test should consist of sending a string to a remote server over UDP, then reading the response from that server and doing something with the result. The only help I need is with the middle two ('send string', then 'receive response') steps of the script:

  1. Send string "ABCDEFG" to server 10.10.10.1 on port UDP 5000
  2. Receive response from server 10.10.10.1

I am relatively familiar with PowerShell, but this is my first time having to deal with sockets, so I am in unfamiliar waters, and I can't seem to make sense of the few examples I have found on posts.

3
Hi, Check the following: leeholmes.com/blog/2009/10/28/… It refers to TCP, but should be modifiable to us UDP instead.Arcass
Thank you, that was a good start and it lead me to some other articles and MSDN documentation, which then opened some other questions... Does this declaration "$RemoteIpEndPoint = [Net.EndPoint](New-Object Net.IPEndPoint($([Net.IPAddress]::Any, 0)))" mean that the server will listen on 0.0.0.0 and on all UDP ports?CRCerr0r
OK, so I see here that 'Any' means it will listen on all local addresses, and here that '0' means it will grab any available port. My question is - if I create a client object, connect to the remote server and send a string, like this: $UDPclient = new-object System.Net.Sockets.UdpClient; $UDPclient.Connect($remoteHost, $port); $UDPclient.Send($sendBytes, $sendBytes.Length); does the OS/.NET handle the return traffic automatically when I do this (to be continued):CRCerr0r
$RemoteIpEndPoint = [Net.EndPoint](New-Object Net.IPEndPoint($([Net.IPAddress]::Any, 0))); $receiveBytes = $UDPclient.Receive([Ref]$RemoteIpEndPoint); with some 'under the covers' magic?CRCerr0r

3 Answers

10
votes

Some time back, I wrote a simple PowerShell script to send a UDP Datagram. See: http://pshscripts.blogspot.co.uk/2008/12/send-udpdatagramps1.html which will get you half way there. I never did do the other half and write the server side of this though!

<#  
.SYNOPSIS 
    Sends a UDP datagram to a port 
.DESCRIPTION 
    This script used system.net.socckets to send a UDP 
    datagram to a particular port. Being UDP, there's 
    no way to determine if the UDP datagram actually 
    was received.  
    for this sample, a port was chosen (20000). 
.NOTES 
    File Name  : Send-UDPDatagram 
    Author     : Thomas Lee - [email protected] 
    Requires   : PowerShell V2 CTP3 
.LINK 
    http://www.pshscripts.blogspot.com 
.EXAMPLE 
#> 

### 
#  Start of Script 
## 

# Define port and target IP address 
# Random here! 
[int] $Port = 20000 
$IP = "10.10.1.100" 
$Address = [system.net.IPAddress]::Parse($IP) 

# Create IP Endpoint 
$End = New-Object System.Net.IPEndPoint $address, $port 

# Create Socket 
$Saddrf   = [System.Net.Sockets.AddressFamily]::InterNetwork 
$Stype    = [System.Net.Sockets.SocketType]::Dgram 
$Ptype    = [System.Net.Sockets.ProtocolType]::UDP 
$Sock     = New-Object System.Net.Sockets.Socket $saddrf, $stype, $ptype 
$Sock.TTL = 26 

# Connect to socket 
$sock.Connect($end) 

# Create encoded buffer 
$Enc     = [System.Text.Encoding]::ASCII 
$Message = "Jerry Garcia Rocks`n"*10 
$Buffer  = $Enc.GetBytes($Message) 

# Send the buffer 
$Sent   = $Sock.Send($Buffer) 
"{0} characters sent to: {1} " -f $Sent,$IP 
"Message is:" 
$Message 
# End of Script 
3
votes

Here's my code:

$client = new-object net.sockets.udpclient(0)

write-host "You are $(((ipconfig) -match 'IPv').split(':')[1].trim()):$($client.client.localendpoint.port)"

$peerIP = read-host "Peer IP address"
$peerPort = read-host "Peer port"

$send = [text.encoding]::ascii.getbytes("heyo")
[void] $client.send($send, $send.length, $peerIP, $peerPort)

$ipep = new-object net.ipendpoint([net.ipaddress]::any, 0)
$receive = $client.receive([ref]$ipep)

echo ([text.encoding]::ascii.getstring($receive))

$client.close()

It does the following:

  1. Creates a UDPClient with an automatically assigned port (0).
  2. Gets the local IP address and UDPClient's automatically assigned port and prints this out to the user.
  3. Retrieves the peer's IP address and port from the user.
  4. Converts string "heyo" from ASCII-encoding into a byte array and sends it to the peer. (I believe it will sit there on the peer's end until it is "received", even for some number of seconds.)
  5. Creates an IPEndPoint that takes a UDP packet from any IP address and any port (0).
  6. Receives whatever data was sent from the peer as a new byte array with that IPEndPoint as a reference parameter (that now stores the origin of the received packet).
  7. Converts the received byte array to an ASCII-encoded string and prints it.
  8. Closes the UDPClient. (Make sure to do this; otherwise, the resources will persist (until you restart PS)!)

The beauty of this script is that it's very simple and straightforward and you can use it both with localhost/127.0.0.1 (in two separate PowerShell windows) or with an external IP address, which, if it's a local IP address, you will know already because the local IP is printed out for you by the script.

Note that there is a SendAsync and a ReceiveAsync for UDPClient, but there is no timeout for them. Some people have cooked up complicated workarounds for this, but you can also just use PowerShell's Start-Job and other *-Job commands and put a receive loop in separately run code.

3
votes

Thomas just gave you the client-side, and here is a simple server-side code:

$port = 2020
$endpoint = new-object System.Net.IPEndPoint ([IPAddress]::Any,$port)
$udpclient = new-Object System.Net.Sockets.UdpClient $port
$content = $udpclient.Receive([ref]$endpoint)
[Text.Encoding]::ASCII.GetString($content)
  • You can test using the IP 127.0.0.1 for your machine at the client-side, opening 2 windows of powershell (one for client-side and another to server-side).

  • For more than 1 packet you may use the code below:

      $port = 2020
      $endpoint = New-Object System.Net.IPEndPoint ([IPAddress]::Any, $port)
      Try {
          while($true) {
              $socket = New-Object System.Net.Sockets.UdpClient $port
              $content = $socket.Receive([ref]$endpoint)
              $socket.Close()
              [Text.Encoding]::ASCII.GetString($content)
          }
      } Catch {
          "$($Error[0])"
      }