Search code examples
c#.netpowershellwinapihardware

How to extract full monitor manufacturer/vendor ID in Windows? (as same as Linux hwinfo --monitor command)


I´m stuck with extracting hardware information of my monitor manufacturer ID in this format: xxxxx_xxxxxxx

Basically, format which provides Linux command hwinfo --monitor as "vendor" parameter seems impossible to reach in standard .NET/PowerShell classes or Win APIs.

Seems like most of .NET instruments provide only limited data about monitor IDs.

I tried most of the .NET/Powershell classes/WinAPIs provided for monitors data:

  • WmiMonitorID
  • Win32_DesktopMonitor
  • WmiMonitorBasicDisplayParams
  • WmiMonitorDescriptorMethods
  • EnumDisplayDevices
  • EnumDisplayMonitors
  • GetMonitorInfo

Always output just limited ID of manufacturer/name:

Manufacturer: BOE06CB

Monitor name: BOE

But I need full version of Manufacturer ID:

Manufacturer: RMJCY_NV15N42

Monitor name: BOEhydis NV15N42 (Dell RMJCY)

*This problem is not caused by insufficient permissions or with obsolete monitor drivers. If i run on same machine for example AIDA64 software, it throws data in mentioned format correctly.

Does anybody know which .NET class / WinAPI could extract monitor manufacturer ID in full format?

Thank you very much!


Solution

  • Very Basic Information Extraction From EDID:

    This code works its way through the registry keys to extract each EDID and returns one PSCustomObject per each monitor found:

    foreach ($Display in Get-ChildItem 'HKLM:\SYSTEM\CurrentControlSet\Enum\DISPLAY') {
       foreach ($Monitor in Get-ChildItem $Display.PSPath) {
          foreach ($edid in Get-ItemProperty "$($Monitor.PSPath)\Device Parameters" -Name 'EDID') {
             $bytes = $edid.EDID
             if ($bytes) {
                #  DDDs: Display Descriptor Definitions
                $dddDisplayProductName = ''
                $dddAlphanumeric = ''
                $dddSerialNumber = ''
                #  Loop through each DDD
                for ($i = 54; $i -lt 109; $i += 18) {
                   #  Get this DDD's type
                   $dddType = $bytes[$i + 3]
                   #  Only interested in DDDs of type 252, 254, and 255
                   if ($dddType -in 252, 254, 255) {
                      #  Get the old DDD value(s) if any
                      $oldDDD = if ($dddType -eq 252) { $dddDisplayProductName } elseif ($dddType -eq 254) { $dddAlphanumeric } else { $dddSerialNumber }
                      #  Get this DDD value
                      $newDDD = [Text.AsciiEncoding]::new().GetString($bytes[($i + 5)..($i + 17)]).Trim()
                      #  Create an array of this type of DDD if necessary
                      $DDD = if ('' -eq $oldDDD) { $newDDD } elseif ($oldDDD -is [array]) { $oldDDD + $newDDD } else { $oldDDD, $newDDD }
                      #  Save the DDD back to appropriate location
                      if ($dddType -eq 252) { $dddDisplayProductName = $DDD } elseif ($dddType -eq 254) { $dddAlphanumeric = $DDD } else { $dddSerialNumber = $DDD }
                   }
                }
                $return = [PSCustomObject]@{
                   ManufacturerID        = '{0:X4}' -f [BitConverter]::ToUInt16($bytes, 8)
                   ProductIDCode         = '{0:X4}' -f [BitConverter]::ToUInt16($bytes, 10)
                   SerialNumber          = '{0:X8}' -f [BitConverter]::ToUInt32($bytes, 12)
                   ManufacturerDate      = $(switch ($bytes[16]) {
                         0 { '{0} (Year of Manufacture)' }
                         255 { '{0} (Model Year)' }
                         Default { "Week $($bytes[16]) of {0} (Year of Manufacture)" }
                      }) -f ($bytes[17] + 1990)
                   EDID_Version          = 'v{0}.{1}' -f $bytes[18], $bytes[19]
                   dddDisplayProductName = $dddDisplayProductName
                   dddAlphanumeric       = $dddAlphanumeric
                   dddSerialNumber       = $dddSerialNumber
                }
                $return
             }
          }
       }
    }
    

    NOTE #1: I'm primarily using this documentation, and it appears that version 1.3 and 1.4 of the EDID are close enough to each other that this code works for both (and both versions appear to be the most common currently in use).
    NOTE #2: The structure provides a place for 4 Display Descriptor Definitions per each monitor, but any DDD can be of any type. This means that a monitor can have more than one DDD of the exact same type. If you look at the example output below, notice that "dddAlphanumeric" for the first monitor is an array, this is because this monitor had 2 DDDs of type alphanumeric.

    Below is the results when ran on my computer:

    ManufacturerID        : AE0D
    ProductIDCode         : 176E
    SerialNumber          : 00000000
    ManufacturerDate      : Week 23 of 2019 (Year of Manufacture)
    EDID_Version          : v1.4
    dddDisplayProductName :
    dddAlphanumeric       : {CMN, N173HCE-G33}
    dddSerialNumber       :
    
    ManufacturerID        : AC10
    ProductIDCode         : 407F
    SerialNumber          : 37363753
    ManufacturerDate      : Week 27 of 2013 (Year of Manufacture)
    EDID_Version          : v1.3
    dddDisplayProductName : DELL U2713HM
    dddAlphanumeric       :
    dddSerialNumber       : 7JNY5375767S
    
    ManufacturerID        : 2D4C
    ProductIDCode         : 7103
    SerialNumber          : 01000E00
    ManufacturerDate      : Week 1 of 2020 (Year of Manufacture) 
    EDID_Version          : v1.3
    dddDisplayProductName : SAMSUNG
    dddAlphanumeric       :
    dddSerialNumber       :
    

    This one is my laptop screen, which is why the SerialNumber 00000000. The serial number is just a number, not the serial number found on the back of the monitor. Since my laptop cannot have a second screen of this type, the manufacture leaves this empty. A more sophisticated extraction of info from EDID would lookup the actual name of the manufacturer from ManufacturerID and product info from ProductIDCode. The week and year appears to match my laptop, an other info is probably correct, but doesn't mean much to me.

    ManufacturerID        : AE0D
    ProductIDCode         : 176E
    SerialNumber          : 00000000
    ManufacturerDate      : Week 23 of 2019 (Year of Manufacture)
    EDID_Version          : v1.4
    dddDisplayProductName :
    dddAlphanumeric       : {CMN, N173HCE-G33}
    dddSerialNumber       :
    

    This is an old monitor I used to have, which is where you may have an issue: How do you know if you are looking at current info, or past info. The retrieved info appears correct.

    ManufacturerID        : AC10
    ProductIDCode         : 407F
    SerialNumber          : 37363753
    ManufacturerDate      : Week 27 of 2013 (Year of Manufacture)
    EDID_Version          : v1.3
    dddDisplayProductName : DELL U2713HM
    dddAlphanumeric       :
    dddSerialNumber       : 7JNY5375767S
    

    This is my current monitor, the info also appears to match what I have. But, as you can see, each manufacture provides drastically different info, with some giving more info while others giving less. In this case, you would probably have to lookup the ProductIDCode 7103 for more detailed info.

    ManufacturerID        : 2D4C
    ProductIDCode         : 7103
    SerialNumber          : 01000E00
    ManufacturerDate      : Week 1 of 2020 (Year of Manufacture) 
    EDID_Version          : v1.3
    dddDisplayProductName : SAMSUNG
    dddAlphanumeric       :
    dddSerialNumber       :