So i will shortly explain the env:
Need to work on a Win2k8 Server with Powershell 4.0
I want to get some information with using SNMP (so printer type and printer MAC address):
$SNMP = new-object -ComObject olePrn.OleSNMP
$SNMP.open($P_IP,"public",2,3000)
$PType = $SNMP.get(".1.3.6.1.2.1.25.3.2.1.3.1")
$PMac = $SNMP.get(".1.3.6.1.2.1.2.2.1.6.2")
echo $PType
echo $PMac
So, the Output looks like this (as an example):
$PType = HP Officejet Pro 251dw Printer
$PMac = ÓÁÔ*
So, first of all i started to check, if i used the right OID - using the command line tool of SnmpSoft Company. There, the output looked well:
OID= OID=.1.3.6.1.2.1.2.2.1.6.2
Type=OctetString
Value= A0 D3 C1 D4 2A 95 ....*.
Alright, so i started to check, what kind of datatype this OID value have: It's octet string. In the next steps, i started to search for possibilities, how to transform this octet string value to some readable hex - until now without any progression. i tried to transform it into Bytes this way:
$bytes = [System.Text.Encoding]::Unicode.GetBytes($PMac)
[System.Text.Encoding]::ASCII.GetString($bytes)
echo $bytes
But the output just confusing me
160
0
211
0
193
0
212
0
42
0
34
32
Tryed to interpret this output without any success. Google can't help me anymore because i don't understand slowly also, how or what to search.
So here i am and hoping to get some help or an advice, how i can change the output of this query to something readable.
It's an encoding problem.
1.3.6.1.2.1.2.2.1.6 is the interface physical address. So I would expect the value to be the MAC address of the interface. Your command line result begins with A0-D3-C1, which is an HP MAC address range, so it's consistent. Your printers MAC address must be A0 D3 C1 D4 2A 95? You didn't state that, so you're leaving me to guess.
I suspect that $PMac is supposed to be a [byte[]] (byte array), but the output is converting it to a string and PowerShell's output system is interpreting it as characters.
Example:
PS C:\> [byte[]]$bytes = 0xa0, 0xd3, 0xc1, 0xd4, 0x2a, 0x95
PS C:\> [System.Text.Encoding]::Default.GetString($bytes)
ÓÁÔ*•
You probably need to do something like this:
$MAC = [System.Text.Encoding]::Default.GetBytes($PMac) | ForEach-Object {
$_.ToString('X2')
}
$MAC = $MAC -join '-'
You may want to use [System.Text.Encoding]::ASCII.GetBytes($PMac) instead, since raw SNMP is supposed to use ASCII encoding. I've no idea what olePrn.OleSNMP uses.
You might also look at one of the SNMP PowerShell modules on the PowerShell Gallery. That will be much easier than dealing with COM object in PowerShell.
I also came across this page on #SNMP's handling of OCTET STRING. #SNMP is a .Net SNMP library, and OCTET STRING appears to be what the underlying type is for this OID. The page describes some of the difficulties of working with this particular object type with .Net. You could also use this library for developing your own Cmdlets in PowerShell; it's available through NuGet.
The output you got is very nearly your expected MAC address
160 0 211 0 193 0 212 0 42 0 34 32
160 is decimal for hexadecimal 0xA0
211 is 0xD3
193 is 0xC1
The additional zeros between each byte may have been added during the Unicode.GetBytes call, which I don't think you'll need to use.
I suspect you'll need to read $PMac as an array of bytes, then do hexadecimal string conversion for each byte. This is probably not the most elegant, but may get the job done:
[byte[]] $arrayofBytes = #(160,211,193)
[string] $hexString
foreach ($b in $arrayofBytes) {
$HexString += [convert]::toString($b,16)
$HexString += ' '
}
Related
I have my bytes stored as string values
like this in file D:\source.txt
208
203
131
132
148
128
128
128
128
128
I just want to read them, and store in another file
I am quite new for powershell, so wrote program like this
$bytes = New-Object System.Collections.ArrayList
foreach($line in [System.IO.File]::ReadLines("D:\source.txt"))
{
[void]$bytes.Add([System.Convert]::ToByte($line));
}
[System.IO.File]::WriteAllBytes("D:\target.zip",[Byte[]]$bytes.ToArray());
So from my undestanding it should get string value, convert it to byte
store it in ArrayList, convert ArrayList to byte array and wrote it to file
And everything goes ok, even if i do echo [Byte[]]$bytes.ToArray() i see correct value
But result file is corrupted, and when i check it byte by byte i see next values
-48
-53
-125
-124
-108
-128
-128
-128
-128
-128
Seems like WriteAllBytes shift my byte values by 128, but why and where?
I am not very professional with powershell, and i cant find anything related in documentation
So can you suggest how i can correct this?
Thanks you for any info
Thanks, i actually found what is the problem. Cause for corruption was incorrect library method for converting from java byte(values from -128...127) to unsigned powershell byte And in hex redactor i`ve got int(8) representation, which is corresponds, if check in powershell(uint) bytes are shown correctly Thanks for help
I am REALLY confused about pack and unpack definition for perl.
Below is the excerpt from perl.doc.org
The pack function converts values to a byte sequence containing
representations according to a given specification, the so-called
"template" argument. unpack is the reverse process, deriving some values
from the contents of a string of bytes.
So I get the idea that pack takes human readable things(such as A) and turn it into binary format. Am I wrong on this interpretation??
So that is my interpreation but then same doc immediately proceeds to put this example which put my understanding exactly the opposite.
my( $hex ) = unpack( 'H*', $mem );
print "$hex\n";
What am I missing?
The pack function puts one or more things together in a single string. It represents things as octets (bytes) in a way that it can unpack reliably in some other program. That program might be far away (like, the distance to Mars far away). It doesn't matter if it starts as something human readable or not. That's not the point.
Consider some task where you have a numeric ID that's up to about 65,000 and a string that might be up to six characters.
print pack 'S A6', 137, $ARGV[0];
It's easier to see what this is doing if you run it through a hex dumper as you run it:
$ perl pack.pl Snoopy | hexdump -C
00000000 89 00 53 6e 6f 6f 70 79 |..Snoopy|
The first column counts the position in the output so ignore that. Then the first two octets represent the S (short, 'word', whatever, but two octets) format. I gave it the number 137 and it stored that as 0x8900. Then it stored 'Snoopy' in the next six octets.
Now try it with a shorter name:
$ perl test.pl Linus | hexdump -C
00000000 89 00 4c 69 6e 75 73 20 |..Linus |
Now there's a space character at the end (0x20). The packed data still has six octets. Try it with a longer name:
$ perl test.pl 'Peppermint Patty' | hexdump -C
00000000 89 00 50 65 70 70 65 72 |..Pepper|
Now it truncates the string to fit the six available spaces.
Consider the case where you immediately send this through a socket or some other way of communicating with something else. The thing on the other side knows it's going to get eight octets. It also knows that the first two will be the short and the next six will be the name. Suppose the other side stored that it $tidy_little_package. It gets the separate values by unpacking them:
my( $id, $name ) = unpack 'S A6', $tidy_little_package;
That's the idea. You can represent many values of different types in a binary format that's completely reversible. You send that packed string wherever it needs to be used.
I have many more examples of pack in Learning Perl and Programming Perl.
I have a quick question. Its most likely user error so I apologize before I begin.
I’m trying to setup threshold for a device so that it will alert us when one of our printers is in a certain state. (Jammed, out of toner, no paper etc) I’ve found the specific oid that handles this. (1.3.6.1.2.1.25.3.5.1.2.1) The specific oid is called hrPrinterDetectedErrorState under the HOST-RESOURCE-MIB. I’ve verified that I can see the oid via SNMPWALK. My problem is interpreting the data its spitting out. What i'm reading in the MIB and what i'm seeing via SNMPWALK are different.
Here is the description of oid from the MIB:
"This object represents any error conditions detected
by the printer. The error conditions are encoded as
bits in an octet string, with the following
definitions:
Condition Bit #
lowPaper 0
noPaper 1
lowToner 2
noToner 3
doorOpen 4
jammed 5
offline 6
serviceRequested 7
inputTrayMissing 8
outputTrayMissing 9
markerSupplyMissing 10
outputNearFull 11
outputFull 12
inputTrayEmpty 13
overduePreventMaint 14
Bits are numbered starting with the most significant
bit of the first byte being bit 0, the least
significant bit of the first byte being bit 7, the
most significant bit of the second byte being bit 8,
and so on. A one bit encodes that the condition was
detected, while a zero bit encodes that the condition
was not detected.
This object is useful for alerting an operator to
specific warning or error conditions that may occur,
especially those requiring human intervention."
The odd part is that SNMPWALK says the oid is a Hex-String while the MIB specifies that it should be a Octet-String. Are the two different? Do I need to convert the data that is output by SNMPWALK somehow to get it to match up with what the MIB is saying?
To test everything, I put the printer into several different “States.” I then ran an SNMPWALK on the device to see what the oid output. Here are the results. As you will see, these results don’t match up to what the MIB specifies.
Case 1: Opened the toner door
Expected Output based on MIB: 4
SNMP Output: 08
Case 2: Removed Toner & Closed the door
Expected Output based on MIB: 1
SNMP Output: 10
Case 3: Placed 1 sheet of paper and printed a 2 page document. The printer ran out of paper.
Expected Output based on MIB: 0 or 1
SNMP Output: #
I’m confused at the output. I just need to know how to read the oid so I can setup thresholds so that when it sees, for example, a 08 it performs a certain action.
Thanks for your help!
You are reading this wrong. The data you receive back should actually be interpreted as a bit array and every bit is its own value for the specific alarm in your case
Expected Output based on MIB: 4
SNMP Output: 08
You actually get back the output:
00001000 00000000
The first byte here covers those values
lowPaper 0
noPaper 1
lowToner 2
noToner 3
doorOpen 4
jammed 5
offline 6
serviceRequested 7
So lowPaper is bit 0, noPaper is bit 1, lowToner is bit 2, etc. And doorOpen is bit 4 and as you can see that bit is set, indicating that the door is open.
EDIT:
This is very dependent on the device and implementation. To know how to parse it right involves a lot of trial and error (at least from my experience). As an example if you get back the message 9104, this could be either be
91 and 04 are separate so you first translate 91 to binary from hex and then the
same thing with 04
91: 10010001
04: 00000100
Which would mean low paper, noToner, service requested and inputTrayEmpty. This looks like the most likely way this works.
If you only get one byte back this then means you should only look for alarms in the first 8 bits. As a example of things you need to look out for: If the only alarm present is doorOpen you could be getting back only 08 but it would actually be 0008 where the first 2 hex chars are actually the second part of the alarms but aren't shown because they are none present. So in your case you actually first have to switch the bytes (if there are 4) parse the first two and the second two on their own and then you get the actual result.
As I said there is no real standard here from what i have seen and you have to just work with it until you are sure you know how the data is sent and how to parse it.
Powershell function to interpret the hrPrinterDetectedErrorState octetstring. (I feel like there's some more often used way to do this?) I've been using this module, but it doesn't even resolve hostnames to ip addresses.
The data property returned is just a string not an octetstring type. None of the printers are snmp v3.
https://www.powershellgallery.com/packages/SNMP/1.0.0.1
A single byte would have to be padded with a zero. Most of the time only one byte is sent. The bytes are in the, I think confusing, order that it's documented in. Converting two bytes to an integer results in a different order (depending on big endian or little endian order).
function snmpmessage {
param($data)
[flags()] Enum hrPrinterDetectedErrorState
{
# more common group
LowPaper = 0x0080
NoPaper = 0x0040
LowToner = 0x0020
NoToner = 0x0010
DoorOpen = 0x0008
Jammed = 0x0004
Offline = 0x0002
ServiceRequested = 0x0001
InputTrayMissing = 0x8000
OutputTrayMissing = 0x4000
MarkerSupplyMissing = 0x2000
OutputNearFull = 0x1000
OutputFull = 0x0800
InputTrayEmpty = 0x0400
OverduePreventMaint = 0x0200
}
$bytes = [byte[]][char[]]$data
if ($bytes.count -eq 1) { $bytes = $bytes[0],0 } # pad 0
$code = [bitconverter]::ToUInt16($bytes, ($startIndex=0))
[hrPrinterDetectedErrorState]$code
}
snmpmessage -join [char[]](1,4)
ServiceRequested, InputTrayEmpty
snmpmessage '#' # 0x40
NoPaper
Or:
$hrPrinterDetectedErrorState = '1.3.6.1.2.1.25.3.5.1.2.1'
$hostname = 'myprinter01'
$ip = (Resolve-DnsName $hostname).ipaddress
$result = Get-SnmpData -ip $ip -oid $hrPrinterDetectedErrorState -v v1
snmpmessage $result.data
LowToner
# ?
# $octetstring = [Lextm.SharpSnmpLib.OctetString]::new($result.data)
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)
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