PNPDevices with 'unknown' status

Started by spl, October 17, 2024, 04:47:16 AM

Previous topic - Next topic

spl

While working on a script to identify, disable, enable a PC/Laptop camera, I found that Windows also contains hidden or not-used devices with a status of 'unknown'. I read one thread about these where a contributor mentioned that MS does not allow these to be displayed with a standard WMI query [which may be inaccurate but I did try w/out success]. However, there is a PS cmdlet Get-PNPDevice which can iterate them. Below I placed a working query using Get-PNPDevice into my StdOut function for use in WB. Probably useless code for anyone reading this, but would appreciate if it could be tested.
;Iterate PNPEntity Devices with unknown status
;save as ..\StdOut_PNPUnknown.wbt
;Stan Littlefield 10/16/2024
;==========================================================
Gosub udfs

args = "Get-PnpDevice | where Status -match 'unknown' | Select-Object Status, Class, FriendlyName | ConvertTo-Csv -NoTypeInformation"
cmd="Powershell"
msg='Unknown PNPEntity Devices'

BoxOpen("Running...",cmd:" ":args:@LF:"PLEASE WAIT...MAY TAKE SOME TIME")
TimeDelay(2)
vals = Get_stdout()
vals = StrReplace(vals,'"','') ;remove quotes
Message(msg,vals) ;will probably be messy so consider file out                      
;optional - create output file with links, for further scraping
;FilePut("c:\temp\UnknownPNPDevices.txt",vals)
Exit
;==========================================================
:udfs
#DefineSubroutine Get_stdout()
ObjectClrOption("useany","System")
objInfo = ObjectClrNew("System.Diagnostics.ProcessStartInfo")
Output=""
timeOut = ObjectType("I2",5000)
objInfo.FileName = cmd
objInfo.RedirectStandardError = ObjectType("BOOL",@TRUE)
objInfo.RedirectStandardOutput = ObjectType("BOOL",@TRUE)
objInfo.UseShellExecute = ObjectType("BOOL",@FALSE)
objInfo.CreateNoWindow = ObjectType("BOOL",@TRUE)
objInfo.Arguments = args
oProcess = ObjectClrNew("System.Diagnostics.Process")
oProcess.StartInfo = objInfo
BoxShut()
oProcess.Start()
oProcess.WaitForExit(timeout)
STDOUT = oProcess.StandardOutput.ReadToEnd()
STDERR = oProcess.StandardError.ReadToEnd()
Output = Output:STDOUT:@CRLF
If STDERR<>""
   Output = Output:"STDERR:":STDERR:@CRLF
Endif
oProcess = 0
objInfo = 0

Return (Output)
#EndSubroutine
Return
;==========================================================
Stan - formerly stanl [ex-Pundit]

spl

Change the arguments variable to reduce duplicate rows in the csv
args = $"
$unk =Get-PnpDevice | where Status -match 'unknown' | Select-Object FriendlyName,Class,Status | ConvertTo-Csv -NoTypeInformation
$unk | Select -Unique
$"
Stan - formerly stanl [ex-Pundit]

td

The following is not an attempt to duplicate the PS based script. It just illustrates using the underlying WMI COM functionality in straight WIL.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Displays plug & play devices on current system
;; with duplicates.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
strComputer = '.'
objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" : strComputer : "\root\cimv2")

; Create a query string.
strQuery = "select * from Win32_PnPEntity"
objPnpDevices = objWMIService.ExecQuery( strQuery, "WQL", 48)    
i = 0
aPNPs = ArrDimension(500, 3) ; Over allocate
aPNPs[i,0] = 'Name'
aPNPs[i,1] = 'PNPClass'
aPNPs[i,2] = 'Status'

Foreach objDevice in objPnpDevices
   i += 1
   aPNPs[i,0] = objDevice.Name
   aPNPs[i,1] = objDevice.PNPClass
   aPNPs[i,2] = objDevice.Status
next
ArrayRedim(aPNPs, i+1, 3) ; Shrink to fit

DispGridFormat=`WWWDLGED,6.2`

DispGridCaption=`PNP Devices`
DispGridX=200
DispGridY=150
DispGridWidth=523
DispGridHeight=413
DispGridNumControls=002
DispGridProcedure=`DEFAULT`
DispGridFont=`DEFAULT`
DispGridTextColor=`DEFAULT`
DispGridBackground=`DEFAULT,0|0|0`
DispGridConfig=0
DispGridDPI=`216,10,20`

DispGrid001=`001,393,515,017,PUSHBUTTON,"PushButton_OK",DEFAULT,"Done",1,10,@csDefButton,DEFAULT,DEFAULT,DEFAULT`
DispGrid002=`001,001,515,387,REPORTVIEW,"ReportView_1",aPNPs,DEFAULT,DEFAULT,30,@csAsort|@csFirstHeader,DEFAULT,DEFAULT,DEFAULT`

ButtonPushed=Dialog("DispGrid")

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Nice, especially the GUI output. I tested and assumed a status of 'error' would equal 'disabled'. But no status for 'unknown' which was the purpose of the original post. The goal was to extend WB reach into something beyond COM, but if that is where WB is and should stay... you win.
Stan - formerly stanl [ex-Pundit]

td

MSFT calls the status of "error" one of the "Nonoperational statuses," which I assume means that the device is present but not in a usable state. The device for which I get that status on my system is currently disabled for security reasons.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Quote from: td on October 23, 2024, 02:24:17 PMMSFT calls the status of "error" one of the "Nonoperational statuses," which I assume means that the device is present but not in a usable state. The device for which I get that status on my system is currently disabled for security reasons.

There is a 'present' property which I believe returns -1/0 for true/false. When tested with camera found the grey-area where the camera could be blocked (so not usable) but WMI indicates present and status of OK. When actually disabled would show present but 'Error' which I coded { !='OK' therefore 'Disabled'} - perhaps a gotcha for coding hubris.

As for the 'unknown' status - seemed to display the variety of USB devices once plugged in, or headsets etc... (Got a thanks about that from 1 person I shared code with).
Stan - formerly stanl [ex-Pundit]

td

Not sure what you mean by "blocked." If an application or service is performing the blocking, WMI may not be able to detect it.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

MSFT describes the "Present" property as "Whether this Plug and Play device is currently in the system."

They also note that "Windows Server 2012 R2, Windows 8.1, Windows Server 2012, Windows 8, Windows Server 2008 R2, Windows 7, Windows Server 2008 and Windows Vista: This property is not supported."
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Quote from: td on October 28, 2024, 07:24:41 AMNot sure what you mean by "blocked." If an application or service is performing the blocking, WMI may not be able to detect it.

I was referring only to cameras. Some laptops have a slider you can adjust to block the camera or turn off in settings. So if you try to use it Windows will pop-up it is blocked with suggestions to unblock. But in either case WMI (at least when I tested on Win10 and Win11) will indicate present and OK. And to your point, WMI/CIM cannot report that. Sorry use of 'blocked' caused confusion.
Stan - formerly stanl [ex-Pundit]

td

Assuming you are referring to the Windows 10/11 Settings applet's Privacy & security > Camera access slider, I can create the same behavior.  I suspect the slider's effect is implemented by setting user deny/allow permissions on the device. The WMI class implementation likely does not check the state of permissions on the device.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade