Search code examples
powershellsnmp

SNMP response mangled by PowerShell?


Consider the following PowerShell code:

$SNMP = New-Object -COMObject OLEPrn.OLESNMP
$SNMP.Open("10.178.230.105", "public", 2, 3000)
$MACAddress = $SNMP.Get(".1.3.6.1.2.1.2.2.1.6.1")
$SNMP.Close()

At this point, $MACAddress is supposed to contain a six-byte string, which when decoded to hex, should be the MAC Address of the printer. This is a Xerox printer, and the first two bytes are supposed to be 0x9C 0x93. However,

for ($i = 0; $i -lt 6; $i++) {
    "{0}: {1:X2}" -f $MACAddress[$i],[BYTE]$MACAddress[$i]
}

throws an error for the first two bytes:

Cannot convert value "œ" to type "System.Byte". Error: "Value was either too large or too small for an unsigned byte."
At Z:\Scripts\Powershell\SNMPscratch.ps1:10 char:4
+    "{0}: {1:X2}" -f $MACAddress[$i],[BYTE]$MACAddress[$i]
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastIConvertible

Cannot convert value "“" to type "System.Byte". Error: "Value was either too large or too small for an unsigned byte."
At Z:\Scripts\Powershell\SNMPscratch.ps1:10 char:4
+    "{0}: {1:X2}" -f $MACAddress[$i],[BYTE]$MACAddress[$i]
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastIConvertible

N: 4E
s: 73
-: 2D
|: 7C

(The last four bytes are correctly converted.)

If I cast to an [int] instead, and make the field for the hex value four characters instead:

for ($i = 0; $i -lt 6; $i++) {
    "{0}: {1:X4}" -f $MACAddress[$i],[int]$MACAddress[$i]
}

I get no error, but...

œ: 0153
“: 201C
N: 004E
s: 0073
-: 002D
|: 007C

... where the first two "bytes" are not 0x9C 0x93, the way they're supposed to be.

What's going wrong, where, and how do I fix it or work around it?

Supplemental information:

I thought that perhaps the encoding was the problem, and tried

[byte[]]$MACAddress = ([System.Text.Encoding]::ASCII).GetBytes($SNMP.Get(".1.3.6.1.2.1.2.2.1.6.1"))

which avoided throwing the error, but generated

63: 003F
63: 003F
78: 004E
115: 0073
45: 002D
124: 007C

which is also wrong - but this makes it look like the problem may be in $SNMP.Get(), rather than in anything I'm doing. If so, is there any alternative, short of using a third-party library, which our Information Security people will not approve?


Solution

  • This works for me, "[System.Text.Encoding]::Default.GetBytes()". Although if the mac address begins with a 0, .Get() returns an empty string. There's always an old version of the Net-SNMP snmpwalk windows binary.

    # snmpmac.ps1
    
    param($PrinterAddress)
    
    $oid = '.1.3.6.1.2.1.2.2.1.6.1' # mac address
    
    $SNMP = New-Object -ComObject olePrn.OleSNMP
    
    foreach($printer in $PrinterAddress) {
      $SNMP.Open($Printer, "public", 2, 3000)
    
      $string = $SNMP.Get($oid)
    
      $MacAddress = ([System.Text.Encoding]::Default.GetBytes($string) |
        % tostring X2) -join '-'
      [pscustomobject]@{Name = $Printer; MacAddress = $MacAddress}
      $SNMP.Close()
    }
    
    
    .\snmpmac a-cp2,a-mfp1,a-mfp2,a-mfp3,a-mfp4
    
    Name        MacAddress
    ----        ----------
    a-cp2
    a-mfp1      58-38-79-23-AE-54
    a-mfp2      58-38-79-23-AD-E8
    a-mfp3      58-38-79-23-AE-70
    a-mfp4      58-38-79-23-B0-B0