'monsernum.vbs '======================================================================================= debugmode=1 'set to 1 to see the results of this script. Set to 0 for unattended execution (as with SMS software distribution) writetosms=1 'set to 1 to write the found data to SMS (which is only useful on SMS clients) dim sMsgString 'for WSH registry reading, which seems to work well with binary values '===================================================================== dim wshShell Set WshShell = WScript.CreateObject("WScript.Shell") On error resume next 'WMI registry reading, which has enumeration '===================================================================== dim oReg Set oReg=GetObject("winmgmts:!root/default:StdRegProv") if err<>0 then if err=-2147467259 then sMsgString = "WMI not available" else sMsgString = "Unexpected Error" end if sMsgString = sMsgString & " Processing Discontinued" Show_Msg(sMsgString) wscript.quit else sMsgString = "WMI Found, Processing Continues" Show_Msg(sMsgString) end if On error goto 0 HKLM=&H80000002 dim EDID1(256) Item=0 suspicious=0 dim EDID dim sernumstr dim namestr dim manyear dim manweek dim manid dim EDIDstatus dim ManufacturedMonth dim DeviceDesc Set loc = CreateObject("WbemScripting.SWbemLocator") Set WbemServices = loc.ConnectServer(, "root\cimv2") Set displays = WbemServices.ExecQuery("SELECT * FROM Win32_DesktopMonitor") if displays.count=0 and debugmode=1 then wscript.echo "No monitors found in WMI" i=0 for each display in displays i=i+1 PNPDeviceID=display.PNPDeviceID if PNPDeviceID<>"" then sMsgString = "WMI Monitor key " & i & ": " & PNPDeviceID Show_Msg(sMsgString) on error resume next EDID=WshShell.RegRead("HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\" & PNPDeviceID & "\Device Parameters\EDID" ) if err=0 then on error goto 0 DeviceDesc = WshShell.RegRead( "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\" & PNPDeviceID & "\DeviceDesc" ) sMsgString = "Monitor (" & DeviceDesc & ") that was found in WMI is also in the registry" Show_Msg(sMsgString) If Parse_EDID=0 AND writetosms=1 Then Put_in_WMI elseif err = -2147024894 then EDID = "" Process_Other_Displays else sMsgString = "PnPDeviceID not Found in Registry, Processing Discontinued" Show_Msg(sMsgString) end if end if next sMsgString = "Script Finished" Show_Msg(sMsgString) '========================================================================= ' PnPDeviceID did not have a corresponding regsitry entry. So Let's ' Enumerate all keys found below the hklm\system\...\enum\display and ' try to find a subkey with serial number information '========================================================================= sub Process_Other_Displays on error resume next sMsgString = "Processing Other Displays" Show_Msg(sMsgString) oReg.EnumKey HKLM, "System\CurrentControlSet\Enum\Display", DeviceKeys for k1 = 0 to ubound(Devicekeys) oReg.EnumKey HKLM, "System\CurrentControlset\Enum\Display\" & DeviceKeys(k1), DeviceSubKeys for k2 = 0 to UBound(DeviceSubKeys) DeviceDesc = "" DeviceDesc = WshShell.RegRead( "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\" & PNPDeviceID & "\DeviceDesc") EDID = wshShell.RegRead("HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\Display\" & Devicekeys(k1) & "\" & DeviceSubKeys(k2) & "\Device Parameters\EDID") if err.number = 0 then if Parse_EDID = 0 and Writetosms = 1 then Put_in_WMI end if elseif err.number = -2147024894 then sMsgString = "EDID not found" Show_Msg(sMsgString) else sMsgString = "Unexpected error" Show_Msg(sMsgString) end if err.clear next next on error goto 0 End Sub '==================================================================== ' Parse the EDID data to retrieve the monitor date, serial number, ' manufacuter and model name/description '==================================================================== Function Parse_EDID on error resume next if EDID(0)=0 AND EDID(1)=255 AND EDID(2)=255 AND EDID(3)=255 AND EDID(4)=255 AND EDID(5)=255 AND EDID(6)=255 AND EDID(7)=0 Then if err<>13 then on error goto 0 Get_Monitor_Manufacturer_and_Date Get_Monitor_Serial_Number Get_Monitor_Name if manyear <> 0 and ManufacturedMonth <> "" and sernumstr <> "" and Namestr <> "" then Parse_EDID=0 EDIDstatus = "Valid" else Parse_EDID=1 end if else sMsgString = "EDID wasn't found" Show_Msg(sMsgString) EDIDstatus="not found" Parse_EDID=1 end if else sMsgString = "EDID is not a valid EDID" Show_Msg(sMsgString) EDIDstatus="invalid" Parse_EDID=2 end if End Function '==================================================================== 'find the Manufacturer and date that the monitor was manufactured on '==================================================================== Sub Get_Monitor_Manufacturer_and_Date ManufacturedMonth = "" manid=EDID(8)*256 + EDID(9) manweek=EDID(16) manweek2=EDID(16) / 4 if manweek2 > 11 then ManufacturedMonth = "December" elseif manweek2 > 10 or manweek2 = 11 then ManufacturedMonth = "November" elseif manweek2 > 9 or manweek2 = 10 then ManufacturedMonth = "October" elseif manweek2 > 8 or manweek2 = 9 then ManufacturedMonth = "September" elseif manweek2 > 7 or manweek2 = 8 then ManufacturedMonth = "August" elseif manweek2 > 6 or manweek2 = 7 then ManufacturedMonth = "July" elseif manweek2 > 5 or manweek2 = 6 then ManufacturedMonth = "June" elseif manweek2 > 4 or manweek2 = 5 then ManufacturedMonth = "May" elseif manweek2 > 3 or manweek2 = 4 then ManufacturedMonth = "April" elseif manweek2 > 2 or manweek2 = 3 then ManufacturedMonth = "March" elseif manweek2 > 1 or Manweek2 = 2 then ManufacturedMonth = "February" elseif manweek2 < 1 or manweek2 = 1 then ManufacturedMonth = "January" end if manyear=EDID(17)+1990 if manweek<>0 AND manyear<>0 then sMsgString = "Monitor manufactured in " & ManufacturedMonth & " of " & manyear else manweek="" manyear="" sMsgString = "No monitor manufactured date found. Possibly the computer is a laptop." end if Show_Msg(sMsgString) End Sub '====================================================================== 'find the monitor serial number. if not found set serial number to NULL '====================================================================== Sub Get_Monitor_Serial_Number sernumstr="" sernum=0 for i=0 to ubound(EDID)-4 if EDID(i)=0 AND EDID(i+1)=0 AND EDID(i+2)=0 AND EDID(i+3)=255 AND EDID(i+4)=0 Then if sernum<>0 then sMsgString = "a second serial number has been found!" Show_Msg(sMsgString) suspicious=1 end if sernum=i+4 end if next if sernum<>0 then endstr=0 sernumstr="" for i=1 to 13 if EDID(sernum+i)=10 then endstr=1 if endstr=0 then sernumstr=sernumstr & chr(EDID(sernum+i)) next sMsgString = "Monitor serial number: " & sernumstr Show_Msg(sMsgString) else sernumstr="" sMsgString = "No monitor serial number found. Possibly the computer is a laptop." Show_Msg(sMsgString) end if End Sub '======================================================================= 'find the monitor name. if not found set monitor name to NULL '======================================================================= Sub Get_Monitor_Name name=0 for i=0 to ubound(EDID)-4 if EDID(i)=0 AND EDID(i+1)=0 AND EDID(i+2)=252 AND EDID(i+3)=0 Then if name<>0 then sMsgString = "a second monitor name has been found!" Show_Msg(sMsgString) suspicious=1 end if name=i+3 end if next if name<>0 then endstr=0 namestr="" for i=1 to 13 if EDID(name+i)=10 then endstr=1 if endstr=0 then namestr=namestr & chr(EDID(name+i)) next sMsgString = "Monitor model name: " & namestr Show_Msg(sMsgString) else namestr="" sMsgString = "No monitor model name was found. Possibly the computer is a laptop." Show_Msg(sMsgString) end if End Sub '=================================================================== 'determine if classes need to be created or just updated. '=================================================================== Sub Put_in_WMI Item=Item+1 sMsgString = "Processing WMI Classes and Properties" Show_Msg(sMsgString) Set loc = CreateObject("WbemScripting.SWbemLocator") Set WbemServices = loc.ConnectServer(, "root\cimv2") On Error Resume Next Set WbemObject = WbemServices.Get("Monitors") 'If this call fails, we need to make the Monitors data class If Err Then sMsgString = "Creating Monitors Class for CimV2 Namespace" Show_Msg(sMsgString) On Error Goto 0 'Retrieve blank class Set WbemObject = WbemServices.Get 'Set class name WbemObject.Path_.Class = "Monitors" 'Add Properties (8 = CIM_STRING, 11 = CIM_BOOLEAN) WbemObject.Properties_.Add "Unit", 19 WbemObject.Properties_.Add "Status", 8 WbemObject.Properties_.Add "SerialNumber", 8 WbemObject.Properties_.Add "ModelName", 8 WbemObject.Properties_.Add "ModelNameDesc",8 WbemObject.Properties_.Add "Manufactured_Month", 8 WbemObject.Properties_.Add "Manufactured_Year", 8 WbemObject.Properties_.Add "ManufacturerId", 8 'Add key qualifier to Type property WbemObject.Properties_("Unit").Qualifiers_.Add "key", True WbemObject.Put_ sMsgString = "added data class to CimV2 Namespace" Show_Msg(sMsgString) End if On Error Goto 0 'Set WbemServices = loc.ConnectServer(, "root\cimv2\SMS") 'On Error Resume Next 'Set WbemObject = WbemServices.Get("Monitors") ''If this call failed, we need to make the Monitors reporting class 'If Err Then ' sMsgString = "Creating Monitors Class in SMS namespace" ' Show_Msg(sMsgString) ' On Error Goto 0 ''we also need to tell the Hardware Inventory Agent to collect the new class ' Set WbemObject = WbemServices.Get("SMS_Class_Template").SpawnDerivedClass_ ' ''Set class name and qualifier values ' WbemObject.Path_.Class = "Monitors" ' WbemObject.Qualifiers_.Add "SMS_Report", True ' WbemObject.Qualifiers_.Add "SMS_Group_Name", "Monitors" ' WbemObject.Qualifiers_.Add "SMS_Group_Name", "Monitors" ' WbemObject.Qualifiers_.Add "SMS_Class_ID", "MICROSOFT|MONITORS|1.0" ' ''Add Properties, set SMS_Report qualifiers to True ' WbemObject.Properties_.Add("Unit", 19).Qualifiers_.Add "SMS_Report", True ' WbemObject.Properties_("Unit").Qualifiers_.Add "key", True ' WbemObject.Properties_.Add("Status", 8).Qualifiers_.Add "SMS_Report", True ' WbemObject.Properties_.Add("SerialNumber", 8).Qualifiers_.Add "SMS_Report", True ' WbemObject.Properties_.Add("ModelName", 8).Qualifiers_.Add "SMS_Report", True ' WbemObject.Properties_.Add("ModelNameDesc",8).Qualifiers_.Add "SMS_Report", True ' WbemObject.Properties_.Add("Manufactured_Month", 8).Qualifiers_.Add "SMS_Report", True ' WbemObject.Properties_.Add("Manufactured_Year", 8).Qualifiers_.Add "SMS_Report", True ' WbemObject.Properties_.Add("ManufacturerId", 8).Qualifiers_.Add "SMS_Report", True ' WbemObject.Put_ ' ' sMsgString = "added reporting class SMS namespace" ' Show_Msg(sMsgString) 'End if 'On Error Goto 0 Set WbemServices = loc.ConnectServer(, "root\cimv2") Set WbemObject = WbemServices.Get("Monitors").SpawnInstance_ ' Store property values (the data) WbemObject.Unit=item if suspicious=1 then EDIDstatus = EDIDstatus & " but suspicious" WbemObject.Status = EDIDstatus WbemObject.SerialNumber = sernumstr WbemObject.ModelName = namestr WbemObject.ModelNameDesc = DeviceDesc WbemObject.Manufactured_Month = ManufacturedMonth WbemObject.Manufactured_Year = manyear WbemObject.ManufacturerId = manid 'WMI will overwrite the existing instance WbemObject.Put_ sMsgString = "wrote the data to WMI" Show_Msg(sMsgString) End Sub '=================================================================== ' subroutine for display error, flowcontrol and informational msgs. ' only used when debugmode = 1 '=================================================================== sub Show_Msg(sMsgParam) if debugmode = 1 then WScript.Echo sMsgParam end if End Sub