I want to send chars to a serial port using powershell:
PS > [Char[]] $request = 'C','A'
PS > $port.Write($request)
But this creates extra whitespace between the characters. Any ideas why?
43 20 41
20 is the extra byte.
It appears that powershell is choosing the overload of Write which takes a single string parameter. In this case it is converting the array to a string before passing it to Write. This conversion inserts the extra space:
[string]$request //C A
specify the other two parameters to use the right overload:
$port.Write($request, 0, $request.length)
Related
I'm trying to replicate the functionality of the following Python snippit in PowerShell:
allowed_mac_separators = [':', '-', '.']
for sep in allowed_mac_separators:
if sep in mac_address:
test = codecs.decode(mac_address.replace(sep, ''), 'hex')
b64_mac_address = codecs.encode(test, 'base64')
address = codecs.decode(b64_mac_address, 'utf-8').rstrip()
It takes a MAC address, removes the separators, converts it to hex, and then base64. (I did not write the Python function and have no control over it or how it works.)
For example, the MAC address AA:BB:CC:DD:E2:00 would be converted to AABBCCDDE200, then to b'\xaa\xbb\xcc\xdd\xe2\x00', and finally as output b'qrvM3eIA'. I tried doing something like:
$bytes = 'AABBCCDDE200' | Format-Hex
[System.BitConverter]::ToString($bytes);
but that produces MethodException: Cannot find an overload for "ToString" and the argument count: "1". and I'm not really sure what it's looking for. All the examples I've found utilizing that call only have one argument. This works:
[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes('AABBCCDDE200'))
but obviously doesn't convert it to hex first and thus yields the incorrect result. Any help is appreciated.
# Remove everything except word characters from the string.
# In effect, this removes any punctuation ('-', ':', '.')
$sanitizedHexStr = 'AA:BB:CC:DD:E2:00' -replace '\W'
# Convert all hex-digit pairs in the string to an array of bytes.
$bytes = [byte[]] -split ($sanitizedHexStr -replace '..', '0x$& ')
# Get the Base64 encoding of the byte array.
[System.Convert]::ToBase64String($bytes)
For an explanation of the technique used to create the $bytes array, as well as a simpler PowerShell (Core) 7.1+ / .NET 5+ alternative (in short: [System.Convert]::FromHexString('AABBCCDDE200')), see this answer.
As for what you tried:
Format-Hex does not return an array of bytes (directly), its primary purpose is to visualize the input data in hex format for the human observer.
In general, Format-* cmdlets output objects whose sole purpose is to provide formatting instructions to PowerShell's output-formatting system - see this answer. In short: only ever use Format-* cmdlets to format data for display, never for subsequent programmatic processing.
That said, in the particular case of Format-Hex the output objects, which are of type [Microsoft.PowerShell.Commands.ByteCollection], do contain useful data, and do contain the bytes of the transcoded characters of input strings .Bytes property, as Cpt.Whale points out.
However, $bytes = ($sanitizedHexStr | Format-Hex).Bytes would not work in your case, because you'd effectively get byte values reflecting the ASCII code points of characters such as A (see below) - whereas what you need is the interpretation of these characters as hex digits.
But even in general I suggest not relying on Format-Hex for to-byte-array conversions:
On a philosophical note, as stated, the purpose of Format-* cmdlets is to produce for-display output, not data, and it's worth observing this distinction, this exception notwithstanding - the type of the output object could be considered an implementation detail.
Format-Hex converts strings to bytes based on first applying a fixed character transcoding (e.g., you couldn't get the byte representation of a .NET string as-is, based on UTF-16 code units), and that fixed transcoding differs between Windows PowerShell and PowerShell (Core):
In Windows PowerShell, the .NET string is transcoded to ASCII(!), resulting in the loss of non-ASCII-range characters - they are transcoded to literal ?
In PowerShell (Core), that problem is avoided by transcoding to UTF-8.
The System.BitConverter.ToString failed, because $bytes in your code wasn't itself a byte array ([byte[]]), only its .Bytes property value was (but didn't contain the values of interest).
That said, you're not looking to reconvert bytes to a string, you're looking to convert the bytes directly to Base64-encoding, as shown above.
Trying to export current temperature from the XML to a text file. The results are are "xx.y" but I only need xx exported to the text file. I've tried several commands but keep striking out. Any ideas?
([xml](Invoke-WebRequest -URI http://w1.weather.gov/xml/current_obs/KSJC.xml).Content).current_observation.temp_f | Out-File c:\temperature.txt
i suspect i am misunderstanding something [this seems alarmingly simple], but here are a few ways to do what it seems you want ... [grin]
$Temperature = '12.3'
$Temperature.Split('.')[0]
[int]$Temperature
[math]::Round([decimal]$Temperature, 0)
the output if each is 12.
the 1st uses the string .Split() method and takes the 1st item in the resulting array
the 2nd uses the [int] type accelerator to coerce the string into an int & rounds it in the process
the 3rd uses the [decimal] type accelerator to coerce the string to a decimal number and the [math]::Round() static method to round the number to 0 decimal places
How can I write the value 255 to the serial port in Powershell ?
$port= new-Object System.IO.Ports.SerialPort COM6,4800,None,8,one
$port.open()
$port.Write([char]255)
$port.Close()
The output of the previous script is 63 (viewed with a serial port monitor).
However $port.Write([char]127) gives 127 as result. If the value is higher than 127 the output is always 63.
Thanks in advance for your help !
Despite your attempt to use [char], your argument is treated as [string], because PowerShell chooses the following overload of the Write method, given that you're only passing a single argument:
void Write(string text)
The documentation for this particular overload states (emphasis added):
By default, SerialPort uses ASCIIEncoding to encode the characters. ASCIIEncoding encodes all characters greater than 127 as (char)63 or '?'. To support additional characters in that range, set Encoding to UTF8Encoding, UTF32Encoding, or UnicodeEncoding.
To send byte values, you must use the following overload:
void Write(byte[] buffer, int offset, int count)
That requires you to:
use cast [byte[]] to cast your byte value(s)
and specify values for offset - the starting byte position as well as count, the number of bytes to copy from the starting byte position.
In your case:
$port.Write([byte[]] (255), 0, 1)
Note: The (...) around 255 isn't required for a single value, but would be necessary to specify multiple, ,-separated values.
Note:
If you want to send entire strings, and those strings include characters outside the ASCII range, you'll need to set the port's character encoding first, as shown in this answer, which also shows an alternative solution based on obtaining a byte-array representation of a string based on the desired encoding (which then allows you to use the same method overload as above).
Try something like this:
$port1 = new-Object System.IO.Ports.SerialPort COM1,4800,None,8,one
$port1.Open()
$data = [System.Text.Encoding]::UTF32.GetBytes([char]255)
$port1.Write( $data )
$port1.ReadExisting()
$port1
$port1.Close()
Should work.
I have a binary file that I need to process, but it contains no line breaks in it.
The data is arranged, within the file, into 104 character blocks and then divided into its various fields by character count alone (no delimiting characters).
I'd like to firstly process the file, so that there is a line break (`n) every 104 characters, but after much web searching and a lot of disappointment, I've found nothing useful yet. (Unless I ditch PowerShell and use awk.)
Is there a Split option that understands character counts?
Not only would it allow me to create the file with nice easy to read lines of 104 chars, but it would also allow me to then split these lines into their component fields.
Can anyone help please, without *nix options?
Cheers :)
$s = get-content YourFileName | Out-String
$a = $s.ToCharArray()
$a[0..103] # will return an array of first 104 chars
You can get your string back the following way, the replace removes space char( which is what array element separators turn into)
$ns = ([string]$a[0..103]).replace(" ","")
Using the V4 Where method with Split option:
$text = 'abcdefghi'
While ($text)
{
$x,$text = ([char[]]$text).where({$_},'Split',3)
$x -join ''
}
abc
def
ghi
I have an UFT16 encoded string theUFT16string. It contains double byte characters. I would like to interate through it Unicode character by Unicode character. I understand that the chunk expressions work by single-byte characters?
An example
We have the following string
abcαβɣ
We want to iterate through it and put each character on a line of its own in another container.
In LiveCode, there are two ways to get a character from a UTF16 string. If the string is displayed in a field, you can do
select char 3 of fld 1
and if you have a Russian or Polish text in the field, it will correctly select 1 character. However, this feature isn't very well developed in LiveCode and will fail with many Chinese, Japanese and Arabic (and other) languages. Therefore, it is better to use bytes for now:
select byte 5 to 6 of fld 1
The latter will also be compatible with future versions of LiveCode, while the former may not be.
Anyway, you have your string in a variable, which means you have to handle the string as bytes (you could use chars, but bytes and chars are dealt with in the same way in this case, because the data is in a variable). You can iterate through the variable with steps of two, i.e. one char at a time:
repeat with x = 1 to number of bytes of theUFT16String step 2
put byte x to x+1 into myChar
// do something with myChar here, e.g. reverse the bytes?
put byte 2 of myChar & char 1 of myChar after myNewString
end repeat
// myNewString now contains the entire theUTF16String in reverse byte order.
(You could do this in 3 lines instead of 4, but for the purpose of the example I have added a line that stores the bytes in var myChar).