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:
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:
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”.
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:
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:
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)”.
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!
https://www.itninja.com/question/count-active-monitors-on-pc - SMal.tmcc 5 years ago
But i have one issue with this report. Report shows me only one screen per computer. - Den4mit 4 years ago
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
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 4 years ago
i.e., Custom Inventory Fields (1) - mcclainr@tessco.com 4 years ago
Or am I wrong? - madro 4 years ago