Powershell UDP script works in ISE but not Console - sockets

First time attempting to work with UDP. I'm harvesting lat/long from a NMEA string in a UDP broadcast. The code below works fine in the ISE but hangs up in the console. I'm running both with Admin rights. Other posts on the topic recommend dot-sourcing, no difference. I suspect it's something to do with how it's handling variables but have hit a wall. Thanks in advance for help.
##########################################################################
#
# Read $GPGGA string from UDP broadcast on port 40181
#
# Convert Degree-Minutes-Seconds format to decimal lat/long
#
# UDP code harvested from http://winpowershell.blogspot.com/2010/01/powershell-udp-clientserver.html
#
#
##########################################################################
# Form a connection point
$endpoint = New-Object system.net.ipendpoint([system.net.ipaddress]::Any,0)
Write-Host "Endpoint: " $endpoint
# Open UDP client
$udpclient = new-Object system.Net.Sockets.Udpclient(40181)
Write-Host "UDP client: " $udpclient
# Grab the datagram
$content = $udpclient.Receive([ref]$endpoint)
Write-Host "Content: " $content
# Put the datagram in $udpstring as type string
$udpstring = [Text.Encoding]::ASCII.GetString($content)
Write-Host "UDP string: " $udpstring
# Close UDP client
$udpclient.Close()
# Get Degree Min Sec format latitude from UDP string
# Explicit typing required in order to do math later
[Double]$DMSlatdeg = $udpstring.Substring(17,2)
$DMSlatmin = $udpstring.Substring(19,2)
# Get North South directional from UDP string
$directNS = $udpstring.Substring(29,1)
# Get Degree Min Sec format longitude from UDP string
# Explicit typing required in order to do math later
[Double]$DMSlongdeg = $udpstring.Substring(31,3)
$DMSlongmin = $udpstring.Substring(34,2)
# Get East West directional from UDP string
$directEW = $udpstring.Substring(44,1)
# Add decimal latitude minutes value to degrees
$declat = ($DMSlatdeg + ($DMSlatmin/60))
# Add decimal longitude minutes value to degrees
$declong = ($DMSlongdeg + ($DMSlongmin/60))
# Output formatted to three decimal places - variable value not changed
Write-Host "Decimal lat: " $declat.ToString("#.###") $directNS
Write-Host "Decimal long: " $declong.ToString("#.###") $directEW
In ISE I get the correct output:
Endpoint: 0.0.0.0:0
UDP client: System.Net.Sockets.UdpClient
Content: 36 71 80 71 71 65 44 [etc]
UDP string: $GPGGA,160516.13,[etc]
Decimal lat: [correct value] N
Decimal long: [correct value] W
In the console, it gets out the first two statements and hangs:
Endpoint: 0.0.0.0:0
UDP client: System.Net.Sockets.UdpClient
Is there something wrong with the way I'm setting $content?

Related

Powershell SNMP converting IP Address: Getting wrong value

How do I properly convert an IP Address gotten via OleSNMP to a useable value?
I'm trying to write a Powershell script to query devices with SNMP and then display the data. Stuff works fine for simple types, but I'm having problems with the IP Addresses (and MAC addresses, but let's stick to IP for now)
Here's what I have (simplified to the problem space):
param ($ipaddr='10.1.128.114', $community='Public')
$snmp = New-Object -ComObject oleprn.OleSNMP
$snmp.open($ipaddr, $community)
$result = $snmp.get(".1.3.6.1.2.1.4.20.1.1.10.1.128.114")
$enc = [system.Text.Encoding]::ASCII
$bytes = $enc.GetBytes($result)
write-host( "bytes:" + $bytes)
Which outputs:
bytes:10 1 63 114
When I expected
bytes:10 1 128 114
For contrast, the snmp-get outputs:
$ snmpget 10.1.128.114 -c Public -v2c -On .1.3.6.1.2.1.4.20.1.1.10.1.128.114
.1.3.6.1.2.1.4.20.1.1.10.1.128.114 = IpAddress: 10.1.128.114
And yes, I realize that in my final script I'll have to walk the table instead of using a direct "get" but I need to fix my parsing first.
As mentioned in the comments, the ASCII encoding substitutes characters outside its valid range with a question mark ?, which is ASCII character 63.
More info is available in the documentation for ASCIIEncoding.GetBytes - search for "?" and you'll find this:
ASCIIEncoding does not provide error detection. Any Unicode character greater than U+007F is encoded as the ASCII question mark ("?").
Note, 0x7F is 127, so since [char] 128 is outside this range, it's being converted to the byte equivalent of ? (which is 63) when you call GetBytes.
Your code is basically doing this this:
$result = ([char] 10) + ([char] 1) + ([char] 128) + ([char] 114)
$encoding = [System.Text.Encoding]::ASCII
$bytes = $encoding.GetBytes($result)
$bytes
# 10
# 1
# 63 (i.e. "?")
# 114
You need to use an encoder which will convert characters higher than 0x7F into the equivalent bytes - something like iso-8859-1 seems to work:
$result = ([char] 10) + ([char] 1) + ([char] 128) + ([char] 114)
$encoding = [System.Text.Encoding]::GetEncoding("iso-8859-1")
$bytes = $encoding.GetBytes($result)
$bytes
# 10
# 1
# 128
# 114

Converting Output to CSV and Out-Grid

I have a file as below.
I want it to convert it to CSV and want to have the out grid view of it for items Drives,Drive Type,Total Space, Current allocation and Remaining space only.
PS C:\> echo $fileSys
Storage system address: 127.0.0.1
Storage system port: 443
HTTPS connection
1: Name = Extreme Performance
Drives = 46 x 3.8T SAS Flash 4
Drive type = SAS Flash
RAID level = 5
Stripe length = 13
Total space = 149464056594432 (135.9T)
Current allocation = 108824270733312 (98.9T)
Remaining space = 40639785861120 (36.9T)
I am new to Powershell but I have tried below code for two of things but it's not even getting me desired output.
$filesys | ForEach-Object {
if ($_ -match '^.+?(?<Total space>[0-9A-F]{4}\.[0-9A-F]{4}\.[0-9A-F]{4}).+?(?<Current allocation>\d+)$') {
[PsCustomObject]#{
'Total space' = $matches['Total space']
'Current allocation' = $matches['Current allocation']
}
}
}
First and foremost, the named capture groups cannot contain spaces.
From the documentation
Named Matched Subexpressions
where name is a valid group name, and subexpression is any valid
regular expression pattern. name must not contain any punctuation
characters and cannot begin with a number.
Assuming this is a single string since your pattern attempts to grab info from multiple lines, you can forego the loop. However, even with that corrected, your pattern does not appear to match the data. It's not clear to me what you are trying to match or your desired output. Hopefully this will get you on the right track.
$filesys = #'
Storage system address: 127.0.0.1
Storage system port: 443
HTTPS connection
1: Name = Extreme Performance
Drives = 46 x 3.8T SAS Flash 4
Drive type = SAS Flash
RAID level = 5
Stripe length = 13
Total space = 149464056594432 (135.9T)
Current allocation = 108824270733312 (98.9T)
Remaining space = 40639785861120 (36.9T)
'#
if($filesys -match '(?s).+total space\s+=\s(?<totalspace>.+?)(?=\r?\n).+allocation\s+=\s(?<currentallocation>.+?)(?=\r?\n)')
{
[PsCustomObject]#{
'Total space' = $matches['totalspace']
'Current allocation' = $matches['currentallocation']
}
}
Total space Current allocation
----------- ------------------
149464056594432 (135.9T) 108824270733312 (98.9T)
Edit
If you just want the values in the parenthesis, modifying to this will achieve it.
if($filesys -match '(?s).+total space.+\((?<totalspace>.+?)(?=\)).+allocation.+\((?<currentallocation>.+?)(?=\))')
{
[PsCustomObject]#{
'Total space' = $matches['totalspace']
'Current allocation' = $matches['currentallocation']
}
}
Total space Current allocation
----------- ------------------
135.9T 36.9T
$unity=[Regex]::Matches($filesys, "\(([^)]*)\)") -replace '[(\)]','' -replace "T",""
$UnityCapacity = [pscustomobject][ordered] #{
Name = "$Display"
"Total" =$unity[0]
"Used" = $unity[1]
"Free" = $unity[2]
'Used %' = [math]::Round(($unity[1] / $unity[0])*100,2)
}``

Grove I2C display not working on Raspberry Pi 3B

I only have my RPi 3B and a I²C display, I don't own any GrovePi hat and I want to show some text to the said display. Is there a way to make it work?
My display.
i2cdetect -y 1 shows this result, meaning the RPi is detecting the I²C display and it should work. But nothing seemed to be showing on the display, except for the full block on the first row.
I've tried literally everything on the internet, some library worked (as in throwing no errors) but the display still stays the same, full block on the first row.
I've installed python3, smbus, smbus2 and i2c-tools. I've changed the address to 3e.
My most recent *.py file. It does write 'LCD printing' yet nothing else works.
I don't find a way to change the contrast of the LCD (no potentiometer or whatsoever)
#!/usr/bin/python3
import smbus2 as smbus
import time
# Define some device parameters
I2C_ADDR = 0x3e # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 16 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
LCD_BACKLIGHT = 0x08 # On
ENABLE = 0b00000100 # Enable bit
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
# Open I2C interface
# bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
def lcd_init():
# Initialise display
lcd_byte(0x33, LCD_CMD) # 110011 Initialise
lcd_byte(0x32, LCD_CMD) # 110010 Initialise
lcd_byte(0x06, LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C, LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28, LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01, LCD_CMD) # 000001 Clear display
time.sleep(E_DELAY)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits << 4) & 0xF0) | LCD_BACKLIGHT
# High bits
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)
# Low bits
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)
def lcd_toggle_enable(bits):
# Toggle enable
time.sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
time.sleep(E_PULSE)
bus.write_byte(I2C_ADDR, (bits & ~ENABLE))
time.sleep(E_DELAY)
def lcd_string(message, line):
# Send string to display
message = message.ljust(LCD_WIDTH, " ")
lcd_byte(line, LCD_CMD)
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]), LCD_CHR)
if __name__ == '__main__':
lcd_init()
while True:
# Send some test
lcd_string("Hello ", LCD_LINE_1)
lcd_string(" World", LCD_LINE_2)
print('LCD printing!')
time.sleep(3)

SHARP Serialport RS232

I am trying get Sony TV model from computer over Serialport.
Here is a documentation (page 80 - how to build query, page 83 - how to get model name).
https://cdn.cnetcontent.com/d1/9d/d19d926b-bb36-4ed3-bd03-af1cad4069da.pdf
Here is my simply script, but, unfortunatelly, always return ERR.
What I did wrong?
$hex = 0x4d,0x4e,0x52,0x44,0x31,0x20,0x20,0x20,0x0d
$com = New-Object System.IO.Ports.Serialport COM4,9600,None,8,one
$com.Open()
$com.Write($hex, 0, $hex.Count)
Start-Sleep -s 2
$read = $com.ReadExisting()
Write-Host "Response: $read" #ERR
$com.Close()
Found response: it return ERR wneh power is off.
When I powered on device over RS-232, script starts respond LE740E insteadof ERR

Python simple UDP server does not receive message with IP options

I have a simple udp server/client setup where I send a message from the client and print it on the server. This works well for a regular IP packet but the message is not received when I add an IP options header to the packet, even though I can sniff the packet using scapy.
Here's the packet without IP options
###[ Ethernet ]###
dst = 00:04:00:00:04:01
src = 00:aa:00:02:00:04
type = 0x800
###[ IP ]###
version = 4L
ihl = 5L
tos = 0x0
len = 47
id = 1
flags =
frag = 0L
ttl = 61
proto = udp
chksum = 0x62f4
src = 10.0.2.101
dst = 10.0.4.101
\options \
###[ UDP ]###
sport = 10001
dport = 3478
len = 27
chksum = 0x2bd1
###[ Raw ]###
load = 'message from a game'
And here's the packet with IP options header:
###[ Ethernet ]###
dst = 00:04:00:00:04:01
src = 00:aa:00:02:00:04
type = 0x800
###[ IP ]###
version = 4L
ihl = 8L
tos = 0x0
len = 59
id = 1
flags =
frag = 0L
ttl = 61
proto = udp
chksum = 0x5fe8
src = 10.0.2.101
dst = 10.0.4.101
\options \
|###[ IPOption ]###
| copy_flag = 1L
| optclass = control
| option = 31L
| length = 12
| value = '\x00\x01\x00\x00RTGAME'
###[ UDP ]###
sport = 10001
dport = 3478
len = 27
chksum = 0x2bd1
###[ Raw ]###
load = 'message from a game'
And here's the UDP server:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', args.port))
while True:
try:
data, addr = sock.recvfrom(1024)
print("received: %s" % data)
except KeyboardInterrupt:
sock.close()
break
I've been stuck on this for a few days and would love if someone could figure it out.
Thanks
have just been playing and the following works as a self-contained/minimal working example for me with Python 3.7.1 under both OSX and Linux
generating a valid set of IP Options:
from scapy.all import IPOption, raw
ipopts = raw(IPOption(
copy_flag=1, optclass='control', option=31,
value='\x00\x01\x00\x00RTGAME'))
(if you don't have Scapy, the above should generate: b'\x9f\x0c\x00\x01\x00\x00RTGAME')
client code:
import socket
from time import sleep
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(('127.0.0.1', 3478))
s.setsockopt(socket.IPPROTO_IP, socket.IP_OPTIONS, ipopts)
while True:
s.send(b'message from a game')
sleep(1)
server code:
import socket
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.bind(('', 3478))
s.setsockopt(socket.IPPROTO_IP, socket.IP_RECVOPTS, 1)
while True:
print(*s.recvmsg(4096, 1024))
this should result in the "server" displaying lines like:
b'message from a game\n' [(0, 6, b'\x9f\x0c\x00\x01\x00\x00RTGAME')] 0 ('127.0.0.1', 46047)
furthermore, I can watch packets move over the network by running:
sudo tcpdump -i lo0 -vvv -n 'udp and port 3478'
at the command line, or this in Scapy:
sniff(iface='lo0', filter='udp and port 3478', prn=lambda x: x.show())
for some reason I don't actually receive the ancillary data containing the IP Options under OSX, but the data shows up in the packet sniffers.
The problem was due to an incorrect IPv4 checksum. I failed to mention in the question that I'm running this in a mininet environment with custom switches. The IP options get added in transit by a switch, but the checksum wasn't updated. Once I fixed that, the packet made it to the server.
Thanks for the help and pointers everyone!