/build/static/layout/Breadcrumb_cap_w.png

Collect external screen inventory information in KACE SMA

Hi everybody,

those of you out there working with the Quest KACE SMA and DELL Clients with the DELLCommand|Monitor software toolkit installed may know that you can see which external screens are connected to your client machines:

9k=

Today I want to show you a script that can provide the same information to you if you do not run Dell machines or you don’t have Dell Command|Monitor installed.
In other words: a universal (Windows-based) solution to get your screen-inventory into your KACE SMA! :)

The solution requires at least two and a third optional step:

1. a VBScript that is run periodically as a KACE SMA script
2. a custom inventory rule (CIR) to read the script results into your inventory
3. (optional) setup a report that gives you an overview of all your screens



1. The Script

The script reads the external screens information from the WMI interface of your Windows installation. Please note that in the present design it just handles EXTERNAL screens. INTERNAL screens of notebooks may be added as well (see the comments inside the VBScript to change that). 
The script run results are saved to the file "c:\windows\MonitorInfo.txt". If you don’t like that path feel free to adjust it, you can edit this at the bottom of the script.

So first you need to copy and paste the following script code into a text editor (I prefer Notepad++) of your choice and save it, for example as “DisplayInformation.vbs”:


Function BytesToString(ByVal Bytes)
  Dim Result, N
  Result = ""
  If IsNull(Bytes) Then
	BytesToString = ""
	Exit Function
  End If
  For N = 0 To UBound(Bytes)
    If CInt(Bytes(N)) <> 0 Then
      Result = Result & Chr(Bytes(N))
    Else
      Exit For
    End If
  Next
  BytesToString = Result
End Function

Function GetConnectionType(ByVal intType)
	GetConnectionType = ""
	Select Case intType
		Case -2 GetConnectionType = "uninitialised"
		Case -1 GetConnectionType = "other"
		Case 0 GetConnectionType = "VGA"
		Case 1 GetConnectionType = "S-Video"
		Case 2 GetConnectionType = "Composite Video"
		Case 3 GetConnectionType = "Component Video"
		Case 4 GetConnectionType = "DVI"
		Case 5 GetConnectionType = "HDMI"
		Case 6 GetConnectionType = "LVDS/MIPI"
		Case 8 GetConnectionType = "D-Jpn"
		Case 9 GetConnectionType = "SDI"
		Case 10 GetConnectionType = "Display Port (external)"
		Case 11 GetConnectionType = "Display Port (internal)"
		Case 12 GetConnectionType = "UDI (external)"
		Case 13 GetConnectionType = "UDI (internal)"
		Case 14 GetConnectionType = "SDTV Dongle"
		Case 15 GetConnectionType = "Miracast"
	End Select
End Function

Dim WMI, Monitors, Output, Monitor, BasicDisplayParams, BDP, ListedSupportedSourceModes, LSSM, MonitorConnectionParams, MCP
Dim MaxHorImgSize, MaxVertImgSize

Dim filesys, filetxt
Set filesys = CreateObject("Scripting.FileSystemObject") 

Output = ""

Set WMI = GetObject("winmgmts:{impersonationlevel=impersonate}!root/wmi")

Set MonitorConnectionParams = WMI.InstancesOf("WmiMonitorConnectionParams")
For Each MCP in MonitorConnectionParams

	'Comment the following line and line 100 (End If) to output internal screens as well
	If MCP.VideoOutputTechnology < 2147483648 And MCP.VideoOutputTechnology > -2147483648 Then

		Set Monitors = WMI.InstancesOf("WmiMonitorID")
			For Each Monitor In Monitors
			
				If Monitor.InstanceName = MCP.InstanceName Then
				
					MaxHorImgSize = 0.0
					MaxVertImgSize = 0.0
					
					If Len(Output) <> 0 Then Output = Output & vbNewLine & vbNewLine
					
					Output = Output & "Description: " & BytesToString(Monitor.UserFriendlyName)
					Output = Output & vbNewLine & "Manufacturer Code: " & BytesToString(Monitor.ManufacturerName) 
					'Output = Output & vbNewLine & "ProductCode ID: " & BytesToString(Monitor.ProductCodeID)
					Output = Output & vbNewLine & "Serialnumber: " & BytesToString(Monitor.SerialNumberID)
					'Output = Output & vbNewLine & "Active: " & CStr(Monitor.Active)
					'Output = Output & vbNewLine & "InstanceName: " & Monitor.InstanceName
					Output = Output & vbNewLine & "Manufactured: " & CStr(Monitor.YearOfManufacture) & " Week " & CStr(Monitor.WeekOfManufacture)
					
					Set BasicDisplayParams = WMI.InstancesOf("WmiMonitorBasicDisplayParams")
					For Each BDP In BasicDisplayParams
						If BDP.InstanceName = Monitor.InstanceName Then
							MaxHorImgSize = BDP.MaxHorizontalImageSize
							MaxVertImgSize = BDP.MaxVerticalImageSize
							If MaxHorImgSize <> 0 And MaxVertImgSize <> 0 Then
								Output = Output & vbNewLine & "Screen Size (cm): " & CStr(MaxHorImgSize) & "x" & CStr(MaxVertImgSize)
								Output = Output & vbNewLine & "Diagonale (inch): " & CStr( Round((Sqr((MaxHorImgSize^2) + (MaxVertImgSize^2))/2.54),1) )
								Output = Output & vbNewLine & "Diagonale (cm): " & CStr( Round((Sqr((MaxHorImgSize^2) + (MaxVertImgSize^2))),1) )
							End If
						End If
					Next
					
					Set ListedSupportedSourceModes = WMI.InstancesOf("WmiMonitorListedSupportedSourceModes")
					For Each LSSM in ListedSupportedSourceModes
						If LSSM.InstanceName = Monitor.InstanceName Then
							Output = Output & vbNewLine & "Best Resolution: " & CStr( LSSM.MonitorSourceModes(LSSM.PreferredMonitorSourceModeIndex).HorizontalActivePixels ) & "x" & CStr( LSSM.MonitorSourceModes(LSSM.PreferredMonitorSourceModeIndex).VerticalActivePixels )
						End If
					Next
					Output = Output & vbNewLine & "Connection Type: " & GetConnectionType(MCP.VideoOutputTechnology)
					
				End If
			Next
	
	'Comment the following line and line 55 (If MCP.VideoOutputTechnology...) to output internal screens as well
	End If
	
Next


WScript.Echo "Detected Screen(s):"
WScript.Echo "-------------------"
WScript.Echo Output

If Len(Output) <> 0 Then
	'recreate output-file
	If filesys.FileExists("c:\windows\MonitorInfo.txt") Then 
		filesys.DeleteFile "c:\windows\MonitorInfo.txt"
	End If 
	filesys.CreateTextFile("c:\windows\MonitorInfo.txt"), True
	'Write
	Set filetxt = filesys.OpenTextFile("c:\windows\MonitorInfo.txt", 8, True)
	filetxt.Write(Output)
	filetxt.Close
End If


Now go to the Scripting section of your KACE SMA and create a new script. Be sure to do the following:

  • Provide a nifty name for the script
  • Script type is “Online KScript”
  • DON’T FORGET TO TICK “ENABLE” AT YOUR SCRIPT AFTER TESTING! (don’t know how often I forgot that...)
  • Select a bunch of machines, labels or even all devices for deployment
  • Select at least one Windows OS as target “Operating Systems”
  • Run as “Local System”
  • Choose an appropriate schedule (I took every 24 hours)
  • Enable “Allow run without a logged-in user”
  • Preferably enable “Run on next connection if offline”
  • Upload your previously created script file (“DisplayInformation.vbs”) as dependency

Inside the script you just need one single task with one single step in the “On Success”-section:

  • Step type is “Launch a program...”
  • “Directory” is:
    $(KACE_SYS_DIR)
  • “File” is:
    cscript.exe
  • Enable “Wait for completion”
  • Disable “Visible”
  • Parameters: (include the quotation marks!)
    //nologo "$(KACE_DEPENDENCY_DIR)\DisplayInformation.vbs"


…so it should look like this in the end:

2Q==

That’s all for the script. Now save everything and test run it on a couple of machines. You should see an appropriate output in the script run’s log file and, of course, in the output file of the script on the local machine ("c:\windows\MonitorInfo.txt" if you did not change it).


2. The Custom Inventory Rule (CIR)

To attach the generated info to the machines inventory you need to create a custom inventory rule that allows the KACE SMA to upload the content to its database.
Here is how:

Go to your “Inventory” and inside the “Software” section, hit the “Choose Action” button and then click “New”.
Z

Now fill the “Name” field. You can enter anything meaningful you like, e.g. “External Screens”.
In “Supported Operating Systems” you have to select at least the Windows OS you chose at the KScript before!
I suggest you pick all Windows Client OS in both cases. Don’t worry, neither the script nor the custom inventory rule will eat up performance or memory on your systems.

Most important: fill the text box “Custom Inventory Rule:” with this one:

ShellCommandTextReturn(cmd /c type C:\Windows\MonitorInfo.txt)


All other fields are not necessary to fill for making this custom inventory rule work. Just save it now and you're done.

After setting up this custom inventory rule you should see output like this in a machines inventory under “Software” in the “Custom Inventory Fields” section:
Z

NOTE THAT THE KSCRIPT MUST HAVE RUN SUCCESSFULLY FIRST ON THE MACHINE(S) AND THE MACHINE(S) NEED TO DO AN INVENTORY BEFORE YOU’LL SEE DATA HERE! (Of course, you can force inventory if you want to)


3. Optional: the Report

If you want a pretty report about all the screens in your network, here is how:

First we need to grab the ID of the custom inventory rule we created in step 2. Therefore go back to your software inventory, locate the custom inventory software you just created and check the tooltip info if you hover the link:

2Q==


You can also right click the link and copy the links’ address to the clipboard, paste it into a text editor and check it out there.

What we need is the value behind the equal-sign.
In my case the URL is https://kacesmaserverurl/adminui/software.php?ID=8793 and so the ID we want is 8793. IT WILL BE A DIFFERENT VALUE IN YOUR SETUP ALMOST FOR SURE. Note it somewhere, we’ll need it in a moment.

Let’s create the report now. Go to the “Reporting” section of the SMA, hit “Choose Action” and then click “New (SQL)”.

Z


Enter a useful name in the “Title” field and assign a fitting category.

I suggest to disable “Show Line Numbers” unless explicitly needed.

I love the report output with “Break on Columns:” set to “Screen square” (without quotation marks. You may change this at any time if you do not like it.

Most important, here is the SQL command required:

Select
  x.Computername,
  x.Computerbenutzer As `Computer user`,
  x.Computermodell As `Computer model`,
  x.Computerhersteller As `Computer manufacturer`,
  x.Computerbauart As `Computer type`,
  x.ComputerSN As `Computer serialnumber`,
  x.ComputerOS As `Computer OS`,
  x.Monitormodell As `Screen model`,
  x.Monitorhersteller As `Screen manufacturer`,
  x.MonitorSN As `Screen serialnumber`,
  x.MonitorSquare As `Screen square`,
  x.MonitorRes As `Screen resolution`,
  x.MonitorConn As `Screen connection type`,
  x.MoniAgeYears As `Screen age (years)`,
  x.MoniAgeDays As `Screen age (days)`
From
  (Select
    mach.NAME As Computername,
    mach.USER_FULLNAME As Computerbenutzer,
    mach.CS_MODEL As Computermodell,
    mach.CS_MANUFACTURER As Computerhersteller,
    mach.CHASSIS_TYPE As Computerbauart,
    mach.BIOS_SERIAL_NUMBER As ComputerSN,
    mach.OS_NAME As ComputerOS,
    SubString_Index(SubString(mci.STR_FIELD_VALUE From Locate('Description: ',
    mci.STR_FIELD_VALUE) + 13), '<br/>', 1) As Monitormodell,
    SubString_Index(SubString(mci.STR_FIELD_VALUE From
    Locate('Manufacturer Code: ', mci.STR_FIELD_VALUE) + 19), '<br/>',
    1) As Monitorhersteller,
    SubString_Index(SubString(mci.STR_FIELD_VALUE From Locate('Serialnumber: ',
    mci.STR_FIELD_VALUE) + 14), '<br/>', 1) As MonitorSN,
    SubString_Index(SubString(mci.STR_FIELD_VALUE From
    Locate('Diagonale (inch): ', mci.STR_FIELD_VALUE) + 18), '<br/>',
    1) As MonitorSquare,
    SubString_Index(SubString(mci.STR_FIELD_VALUE From
    Locate('Best Resolution: ', mci.STR_FIELD_VALUE) + 17), '<br/>',
    1) As MonitorRes,
    SubString_Index(SubString(mci.STR_FIELD_VALUE From
    Locate('Connection Type: ', mci.STR_FIELD_VALUE) + 17), '<br/>',
    1) As MonitorConn,
    SubString_Index(SubString(mci.STR_FIELD_VALUE From Locate('Manufactured: ',
    mci.STR_FIELD_VALUE) + 14), '<br/>', 1) As MoniAgeInfo,
    SubString_Index(SubString(mci.STR_FIELD_VALUE From Locate('Manufactured: ',
    mci.STR_FIELD_VALUE) + 14), ' Week ', 1) As MoniAgeYear,
    LPad(SubString_Index(SubString(mci.STR_FIELD_VALUE From Locate(' Week ',
    mci.STR_FIELD_VALUE) + 6), '<br/>', 1), 2, '0') As MoniAgeWeek,
    Str_To_Date(Concat(SubString_Index(SubString(mci.STR_FIELD_VALUE From
    Locate('Manufactured: ', mci.STR_FIELD_VALUE) + 14), ' Week ', 1),
    LPad(SubString_Index(SubString(mci.STR_FIELD_VALUE From Locate(' Week ',
    mci.STR_FIELD_VALUE) + 6), '<br/>', 1), 2, '0'), ' Monday'), '%x%v %W') As
    MoniAgeRefDate,
    DateDiff(Now(),
    Str_To_Date(Concat(SubString_Index(SubString(mci.STR_FIELD_VALUE From
    Locate('Manufactured: ', mci.STR_FIELD_VALUE) + 14), ' Week ', 1),
    LPad(SubString_Index(SubString(mci.STR_FIELD_VALUE From Locate(' Week ',
    mci.STR_FIELD_VALUE) + 6), '<br/>', 1), 2, '0'), ' Monday'), '%x%v %W')) As
    MoniAgeDays,
    Round((DateDiff(Now(),
    Str_To_Date(Concat(SubString_Index(SubString(mci.STR_FIELD_VALUE From
    Locate('Manufactured: ', mci.STR_FIELD_VALUE) + 14), ' Week ', 1),
    LPad(SubString_Index(SubString(mci.STR_FIELD_VALUE From Locate(' Week ',
    mci.STR_FIELD_VALUE) + 6), '<br/>', 1), 2, '0'), ' Monday'), '%x%v %W')) /
    365), 1) As MoniAgeYears
  From
    MACHINE mach Inner Join
    MACHINE_CUSTOM_INVENTORY mci
      On mach.ID = mci.ID
  Where
    mci.SOFTWARE_ID = 8793 And
    mci.STR_FIELD_VALUE Like '%Description: %') As x
Order By
  `Screen square` Desc,
  x.MoniAgeRefDate Desc

Before saving and testing your report it is REQUIRED you change the software ID in the line “mci.SOFTWARE_ID = 8793 And” to the value you noted down before or the report won’t show anything!

If everything went right and your machines ran the script and at least one inventory cycle (already mentioned in step 2) you should now be able to run the report and get a list table of all your screens!

 

That’s it for today, if you got any questions drop a comment below!

 


Comments

  • THX. Works great! - TechDave 4 years ago
  • You can use an external program also to get any monitor on any brand of machine.
    https://www.itninja.com/question/count-active-monitors-on-pc - SMal.tmcc 4 years ago
  • Great Work! - AFCUjstrick 4 years ago
  • THX. It works great.
    But i have one issue with this report. Report shows me only one screen per computer. - Den4mit 4 years ago
    • Hi Den4mit, you're welcome. Can you provide some info about the screen that is missing? - chrpetri 4 years ago
      • Hi! Yes all second screens are missing in report. In custum inventory i can see all external screens , but not in this report.

        For example:
        2) INVENTORY: External Screens: Description: DELL U2412M
        Manufacturer Code: DEL
        Serialnumber: 0FFXD4770NHS
        Manufactured: 2014 Week 28
        Screen Size (cm): 52x32
        Diagonale (inch): 24
        Diagonale (cm): 61,1
        Best Resolution: 1920x1200
        Connection Type: Display Port (external)

        Description: DELL U2412M
        Manufacturer Code: DEL
        Serialnumber: 0FFXD4770N6S
        Manufactured: 2014 Week 28
        Screen Size (cm): 52x32
        Diagonale (inch): 24
        Diagonale (cm): 61,1
        Best Resolution: 1920x1200
        Connection Type: Display Port (external)



        The second one is not in report. - Den4mit 4 years ago
    • Same here. I have three monitors connected.
      Here are the custom Inventory Fields:

      Description: HP E243
      Manufacturer Code: HPN
      Serialnumber: CNC9331CZL
      Manufactured: 2019 Week 33
      Screen Size (cm): 53x30
      Diagonale (inch): 24
      Diagonale (cm): 60.9
      Best Resolution: 1920x1080
      Connection Type: Display Port (external)

      Description: HP E243
      Manufacturer Code: HPN
      Serialnumber: CNC9331CZS
      Manufactured: 2019 Week 33
      Screen Size (cm): 53x30
      Diagonale (inch): 24
      Diagonale (cm): 60.9
      Best Resolution: 1920x1080
      Connection Type: Display Port (external)

      Description: HP E243
      Manufacturer Code: HPN
      Serialnumber: CNK9320M3F
      Manufactured: 2019 Week 32
      Screen Size (cm): 53x30
      Diagonale (inch): 24
      Diagonale (cm): 60.9
      Best Resolution: 1920x1080
      Connection Type: Display Port (external) [string]

      I also notice that two of the monitors are connected via Display Port, but the third is actually HDMI (serial Number CNC9331CZL).
      And there is also that [string] at the end of the final monitor connection type. This [string] is not in the text file created by the script.

      The report only shows a single monitor (the first one in the list above). - mcclainr@tessco.com 3 years ago
      • One thing I've noticed is that my Custom Inventory Fields only shows 1 record even though there are three monitors.

        i.e., Custom Inventory Fields (1) - mcclainr@tessco.com 3 years ago
  • Thanks for this post, it is very useful for me. But I noticed something, it doesn't work if the machine has 3 monitors for example only if it has 2.
    Or am I wrong? - madro 3 years ago
  • Did anyone figure out how to get all the monitors reported in the CIR? I though it had to do with the join but no matter what I do left, right, inner, outer... same results. - dmulkeen 2 years ago
  • I, too, am not seeing multiple monitors in the report. It looks like we need to have a "Group By" in the join on the SQL statement but I can't get it to work. Can anyone out there provide some insight? Also, some of the monitors I am seeing have a non unique serial number, eg "1". I am wondering if we can set a counter and concatenate that with the ProductCode ID (which is commented out) to come up with a different unique number to identify monitors? I'm kind of surprised that Kace hasn't resolved this shortcoming in their inventory. - chitriguy 2 years ago
  • Any update to try and pull multiple monitors per device in the report? - aroszel 1 year ago
  • Hello, I am also running into the issue of the report only showing 1 monitor despite the CIR reporting all 4 of mine? Is there a known fix for this? - gumshew 1 year ago
This post is locked
 
This website uses cookies. By continuing to use this site and/or clicking the "Accept" button you are providing consent Quest Software and its affiliates do NOT sell the Personal Data you provide to us either when you register on our websites or when you do business with us. For more information about our Privacy Policy and our data protection efforts, please visit GDPR-HQ