0

I've searched for similar variants to what I'm trying to accomplish, and I can do it with no trouble on Linux, but Win10 is giving me a heck of a time. I'm sure it's something extremely simple that I'm simply overlooking, or a syntax I'm scrambling. What I'm trying to accomplish is to have a script run after boot to query the status of a specific driver and, if the status is OK, just continue on its merry way, or, if it has a problem, reinstall the driver from a specific source.

I have no problem doing the query the driver state part, or the reinstall part, but I can't manage to get it to recognize the fault condition to install the driver, or bypass it if everything is OK. Right now, I have the following to query the driver state:

wmic path win32_VideoController WHERE VideoProcessor="Video Processor Name" GET Status > C:\destination.txt

This gives me an output file consisting of four lines, top two empty, the third being "Status" and the fourth being whatever the status value is. (E.g. "OK", "Degraded", et cetera.)

For the end result, I'd like to then run a small script which reads whatever that status value is, and then determines whether to skip to the end, or install the driver from source using:

pnputil.exe -a c:\INF_Source_Dir\INF_Source_File.inf

For the middle bit, being that I don't know explicitly what that source variable is, I can't do a Findstr for it, and I've tried variants of the following, but none seem to change the variable I name:

set vidstatus=
for /F "tokens=" %%a in (c:\destination.txt) do set vidstatus=!vidstatus!
     set var!vidstatus!=%%x

I haven't delved into PowerShell yet to see if I can do something similar, but I'm down for exploring that, too, starting here and then narrowing it down to just the problematic driver, but I'd still have to resolve taking that output and calling (or skipping) the driver install.

$DeviceState = Get-WmiObject -Class Win32_PnpEntity -ComputerName localhost -Namespace Root\CIMV2 | Where-Object {$_.ConfigManagerErrorCode -gt 0 
}
 
 
 
$DevicesInError = foreach($Device in $DeviceState){
 $Errortext = switch($device.ConfigManagerErrorCode){
        0  {"This device is working properly."}
        1  {"This device is not configured correctly."}
        2  {"Windows cannot load the driver for this device."}
        3  {"The driver for this device might be corrupted, or your system may be running low on memory or other resources."}
        4  {"This device is not working properly. One of its drivers or your registry might be corrupted."}
        5  {"The driver for this device needs a resource that Windows cannot manage."}
        6  {"The boot configuration for this device conflicts with other devices."}
        7  {"Cannot filter."}
        8  {"The driver loader for the device is missing."}
        9  {"This device is not working properly because the controlling firmware is reporting the resources for the device incorrectly."}
        10  {"This device cannot start."}
        11  {"This device failed."}
        12  {"This device cannot find enough free resources that it can use."}
        13  {"Windows cannot verify this device's resources."}
        14  {"This device cannot work properly until you restart your computer."}
        15  {"This device is not working properly because there is probably a re-enumeration problem."}
        16  {"Windows cannot identify all the resources this device uses."}
        17  {"This device is asking for an unknown resource type."}
        18  {"Reinstall the drivers for this device."}
        19  {"Failure using the VxD loader."}
        20  {"Your registry might be corrupted."}
        21  {"System failure: Try changing the driver for this device. If that does not work, see your hardware documentation. Windows is removing this device."}
        22  {"This device is disabled."}
        23  {"System failure: Try changing the driver for this device. If that doesn't work, see your hardware documentation."}
        24  {"This device is not present, is not working properly, or does not have all its drivers installed."}
        25  {"Windows is still setting up this device."}
        26  {"Windows is still setting up this device."}
        27  {"This device does not have valid log configuration."}
        28  {"The drivers for this device are not installed."}
        29  {"This device is disabled because the firmware of the device did not give it the required resources."}
        30  {"This device is using an Interrupt Request (IRQ) resource that another device is using."}
        31  {"This device is not working properly because Windows cannot load the drivers required for this device."}
                }
    [PSCustomObject]@{
        ErrorCode = $device.ConfigManagerErrorCode
        ErrorText = $Errortext
        Device = $device.Caption
        Present = $device.Present
        Status = $device.Status
        StatusInfo = $device.StatusInfo
    }
}
 
if(!$DevicesInError){
    write-host "Healthy"
} else {
    $DevicesInError
}
Gerhard
  • 22,678
  • 7
  • 27
  • 43
Kreegah
  • 3
  • 2
  • 1
    Are you getting an error using Powershell? – Abraham Zinala May 06 '21 at 22:00
  • Right now, no, but I also don't (yet) know what error condition gets reported when the intermittent problem I'm trying to work around manifests. So I'm only working on knowing -where- the variable reported state will appear, rather than what it says. However, I will probably know the what it says (in both cases) on Monday, if our enterprise IT folks' pattern holds true as it has for the past month. :D (basically, if driver status = x, do nothing. if driver status = y, reinstall from specified source.) – Kreegah May 06 '21 at 22:34
  • The `FOR` command syntax is incorrect. If you need to run multiple lines of code after the `DO`, you need to use parentheses. You are also using delayed expansion but your code does not enable it. – Squashman May 06 '21 at 23:44
  • You could check the same `ConfigManagerErrorCode` property. of `Win32_VideoController`. For a single line batch/cmd example: `WMIC.exe Path Win32_VideoController Where "Name='Video Processor Name' And ConfigManagerErrorCode='2' Or ConfigManagerErrorCode='3' Or ConfigManagerErrorCode='4' Or ConfigManagerErrorCode='18' Or ConfigManagerErrorCode='21' Or ConfigManagerErrorCode='23' Or ConfigManagerErrorCode='24' Or ConfigManagerErrorCode='28' Or ConfigManagerErrorCode='31'" Get ConfigManagerErrorCode 2>NUL | findstr.exe "[2348]" >NUL && pnputil.exe -a C:\INF_Source_Dir\INF_Source_File.inf` – Compo May 07 '21 at 00:28
  • As an aside: The CIM cmdlets (e.g., `Get-CimInstance`) superseded the WMI cmdlets (e.g., `Get-WmiObject`) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell [Core] (version 6 and above), where all future effort will go, doesn't even _have_ them anymore. For more information, see [this answer](https://stackoverflow.com/a/54508009/45375). – mklement0 May 07 '21 at 01:24
  • wont the schemes listed under this [question](https://stackoverflow.com/questions/3325081/how-to-check-if-a-service-is-running-via-batch-file-and-start-it-if-it-is-not-r) work ? – Neelabh Mam May 07 '21 at 16:14

3 Answers3

0

The accepted answer in this question should work here as well.. I just tried it by stopping a service and then giving that service's name in the script.. it started it. Every driver would have a corresponding service entry and sc commands would work on a driver service as well. Adapting this to inject fault or bypass conditions should be doable.. reproduced from the answer of the highlighted question:

enter image description here

Neelabh Mam
  • 300
  • 6
  • 10
  • Ahhh, I didn't spot that question, since I wasn't looking for something specific to a service, but I think I see how to modify it for the driver status output, particularly with Stephan's reference below. Thanks! – Kreegah May 09 '21 at 16:45
0

wmic output has a few quirks. The most important here is:
line endings are not the usual CRLF, but CRCRLF. A seemingly empty line isn't empty, it still has the superfluous CR. Also this CR may become part of your variable.
There are several possibilities to "correct" this behavior. The safest and most general is to use another for loop:

for /f "delims=" %%a in ('wmic path win32_VideoController WHERE VideoProcessor^="Intel(R) UHD Graphics Family" GET Status /value^|find "="') do for /f "delims=" %%b in ("%%a") do set "%%b"
echo "%status%"
Stephan
  • 53,940
  • 10
  • 58
  • 91
  • Ah! I did not realize that, and that WOULD explain why I can change the variable manually, but the script reading the file output doesn't. I will tinker further, thank you! – Kreegah May 09 '21 at 16:37
  • Yup, that did it! Thank you! – Kreegah May 10 '21 at 14:14
0

As an aside, @Mklement0 pointed me to Get-CimInstance, which provided me with the following alternative means of doing what I was trying to do, with PowerShell. This uninstalls the corrupted driver and reinstalls it from a known good source:

$DriverInf = (Get-CimInstance Win32_VideoController -Filter "AdapterCompatibilit='Intel Corporation'").InfFilename
$SourceInf = [driver source directory\filename]
if (Get-CimInstance Win32_VideoController -filter "AdapterCompatibility='Intel Corporation'" | Where-Object {$_.ConfigManagerErrorCode -gt 0}) {pnputil.exe /delete-driver $DriverInf /uninstall /force ; pnputil.exe /add-driver $SourceInf /install |Outfile -FilePath [logfile location\filename]} else {"$Driverinf Video Driver OK" | Out-File -FilePath [Path to status file\VideoStatus.txt]}
Kreegah
  • 3
  • 2