问题
Using DevCon utility, I ran this command to get the list of all of the drivers installed in the computer.
devcon.exe driverfiles * > drivers.txt
The output looks like this:
USB\ROOT_HUB20\4&361B340A&0
Name: USB Root Hub
Driver installed from C:\windows\INF\usbport.inf [ROOTHUB.Dev]. 2 file(s) used by driver:
C:\windows\system32\drivers\usbhub.sys
C:\windows\system32\drivers\usbd.sys
ACPI\PNP0C09\1
USB\ROOT_HUB20\4&361B340A&1
Name: USB Root Hub
Driver installed from C:\windows\INF\usbport.inf [ROOTHUB.Dev]. 2 file(s) used by driver:
C:\windows\system32\drivers\usbhub.sys
C:\windows\system32\drivers\usbd.sys
I then used PowerShell script to parse the file. Thanks to TheMadTechnician.
(Get-Content C:\Path\To\File.txt) -join "`r`n" -Split "(?m)^(?=\S)" |
Where{$_} |
ForEach{
Clear-Variable Files,Driver,Name,HardwareID
$Files = @()
$HardwareID = ($_ -split "`r`n")[0].trim()
Switch -regex ($_ -split "`r`n"){
"^\s+Name:" {$Name = ($_ -split ':',2)[-1].trim();Continue}
"^\s+.:\\" {$Files += $_.trim();continue}
"^\s+Driver" {$Driver = [RegEx]::Matches($_,"(?<=Driver installed from )(.+?)(?= \[)").value;continue}
}
[PSCustomObject]@{'HardwareID' = $HardwareID;'Name' = $Name; 'Files' = $Driver; 'FileVersion' = If(Test-Path $_.Trim()){[System.Diagnostics.FileVersionInfo]::GetVersionInfo($_.trim()).FileVersion}}
$Files | ForEach{ [PSCustomObject]@{'HardwareID' = $HardwareID;'Name' = $Name; 'Files' = $_; 'FileVersion' = If(Test-Path $_.Trim()){[System.Diagnostics.FileVersionInfo]::GetVersionInfo($_.trim()).FileVersion}Else{'File Not Found'}}}
Now, the output after running the script is:
HardwareID Name Files FileVersion
---------- ---- ----- -----------
USB\ROOT_HUB20\4&361B340A&0 USB Root Hub C:\windows\INF\usbport.inf
USB\ROOT_HUB20\4&361B340A&0 USB Root Hub C:\windows\system32\drivers\usbhub.sys 6.3.9600.17238 (winblue_gdr.140723-2018)
USB\ROOT_HUB20\4&361B340A&0 USB Root Hub C:\windows\system32\drivers\usbd.sys 6.3.9600.17195 (winblue_gdr.140530-1506)
ACPI\PNP0C09\1
USB\ROOT_HUB20\4&361B340A&1 USB Root Hub C:\windows\INF\usbport.inf
USB\ROOT_HUB20\4&361B340A&1 USB Root Hub C:\windows\system32\drivers\usbhub.sys 6.3.9600.17238 (winblue_gdr.140723-2018)
USB\ROOT_HUB20\4&361B340A&1 USB Root Hub C:\windows\system32\drivers\usbd.sys 6.3.9600.17195 (winblue_gdr.140530-1506)
THE PROBLEM
I would like to add an extra column with driver version.
How can I find the driver version and list it next to the name column? Thank you!
EDIT
The code below parses driver version from the INF file. I am not experienced with PowerShell, so how can I used this bit of information and incorporate it with the above code to add an extra column and list driver version; preferably, next to Name column.
$pattern = 'DriverVer\s*=\s*(?:\d+/\d+/\d+,)?(.*)'
Select-String -Pattern $pattern -Path $path |
select -Expand Matches -First 1 |
% { $_.Groups[1].Value }
# $path = the INF file
回答1:
Adding a new column is relatively simple. The columns are listed because they are properties of the object in the array. So right now we have object that are built like this (the driver line is similar, and then we pipe all remaining files into this, line breaks added for ease of reading):
[PSCustomObject]@{
'HardwareID' = $HardwareID
'Name' = $Name
'Files' = $_
'FileVersion' = If(Test-Path $_.Trim()){[System.Diagnostics.FileVersionInfo]::GetVersionInfo($_.trim()).FileVersion}Else{'File Not Found'}
}
From that we get the four columns 'HardwareID, 'Name', 'Files', and 'FileVersion'. If you want to add a column you can simply insert another property. In this case you want to add a new column next to Name that has the version of the driver for each item. We can simply re-purpose the line that currently outputs the driver file path (with missing version number) for each item:
[PSCustomObject]@{'HardwareID' = $HardwareID;'Name' = $Name; 'Files' = $Driver; 'FileVersion' = If(Test-Path $_.Trim()){[System.Diagnostics.FileVersionInfo]::GetVersionInfo($_.trim()).FileVersion}}
With that line we can just remove the bit in there that tries to list anything in the 'FileVersion' column, and add a new one in there for 'DriverVersion' using the code that you supplied (with some minor modifications). We're going to move the $Pattern =
line to be the first line of the script, since we don't need to re-assign that for each iteration of the loop. Then we are going to assign the rest of your code to the new 'DriverVersion' property/column, and wrap it in a If($Driver){}
statement, so that it doesn't throw errors for entries that don't have a driver listed. So that now looks like this:
[PSCustomObject]@{
'HardwareID' = $HardwareID
'Name' = $Name
'DriverVersion' = If($Driver){Select-String -Pattern $pattern -Path $driver | select -Expand Matches -First 1 |%{ $_.Groups[1].Value }}else{''}
'Files' = $Driver
'FileVersion' = '' }
Now, since we added that property to that line, we need to update the next line as well so that it includes that property as well (albeit with a blank value):
$Files | ForEach{ [PSCustomObject]@{'HardwareID' = $HardwareID;'Name' = $Name; 'DriverVersion'= ''; 'Files' = $_; 'FileVersion' = If(Test-Path $_.Trim()){[System.Diagnostics.FileVersionInfo]::GetVersionInfo($_.trim()).FileVersion}Else{'File Not Found'}}}
The updated code as a whole would look something like:
$pattern = 'DriverVer\s*=\s*(?:\d+/\d+/\d+,)?(.*)'
(Get-Content C:\Path\To\File.txt) -join "`r`n" -Split "(?m)^(?=\S)" |
Where{$_} |
ForEach{
Clear-Variable Files,Driver,Name,HardwareID,DriverVer -ea SilentlyContinue
$Files = @()
$HardwareID = ($_ -split "`r`n")[0].trim()
Switch -regex ($_ -split "`r`n"){
"^\s+Name:" {$Name = ($_ -split ':',2)[-1].trim();Continue}
"^\s+.:\\" {$Files += $_.trim();continue}
"^\s+Driver" {$Driver = [RegEx]::Matches($_,"(?<=Driver installed from )(.+?)(?= \[)").value;continue}
}
[PSCustomObject]@{
'HardwareID' = $HardwareID
'Name' = $Name
'DriverVersion' = If($Driver){Select-String -Pattern $pattern -Path $driver | select -Expand Matches -First 1 |%{ $_.Groups[1].Value }}else{''}
'Files' = $Driver
'FileVersion' = '' }
$Files | ForEach{ [PSCustomObject]@{'HardwareID' = $HardwareID;'Name' = $Name; 'DriverVersion'= ''; 'Files' = $_; 'FileVersion' = If(Test-Path $_.Trim()){[System.Diagnostics.FileVersionInfo]::GetVersionInfo($_.trim()).FileVersion}Else{'File Not Found'}}}
}|ft
This now outputs something along the lines of:
HardwareID Name DriverVersion Files FileVersion
---------- ---- ------------- ----- -----------
USB\ROOT_HUB20\4&361B340A&0 USB Root Hub 6.3.9600.17238 C:\windows\INF\usbport.inf
USB\ROOT_HUB20\4&361B340A&0 USB Root Hub C:\windows\system32\drivers\usbhub.sys 6.3.9600.17238 (winblue_gdr.140723-2018)
USB\ROOT_HUB20\4&361B340A&0 USB Root Hub C:\windows\system32\drivers\usbd.sys 6.3.9600.17195 (winblue_gdr.140530-1506)
ACPI\PNP0C09\1
USB\ROOT_HUB20\4&361B340A&1 USB Root Hub 6.3.9600.17238 C:\windows\INF\usbport.inf
USB\ROOT_HUB20\4&361B340A&1 USB Root Hub C:\windows\system32\drivers\usbhub.sys 6.3.9600.17238 (winblue_gdr.140723-2018)
USB\ROOT_HUB20\4&361B340A&1 USB Root Hub C:\windows\system32\drivers\usbd.sys 6.3.9600.17195 (winblue_gdr.140530-1506)
ACPI\PNP0C09\2
USB\ROOT_HUB20\4&361B340A&2 6.3.9600.16384 C:\windows\INF\cmbatt.inf
USB\ROOT_HUB20\4&361B340A&2 C:\windows\system32\DRIVERS\CmBatt.sys 6.3.9600.16384 (winblue_rtm.130821-1623)
USB\ROOT_HUB20\4&361B340A&2 C:\windows\system32\DRIVERS\battc.sys 6.3.9600.16384 (winblue_rtm.130821-1623)
ACPI\PNP0C0A\2 Microsoft ACPI-Compliant Control Method Battery 6.3.9600.16384 C:\windows\INF\cmbatt.inf
ACPI\PNP0C0A\2 Microsoft ACPI-Compliant Control Method Battery C:\windows\system32\DRIVERS\CmBatt.sys 6.3.9600.16384 (winblue_rtm.130821-1623)
ACPI\PNP0C0A\2 Microsoft ACPI-Compliant Control Method Battery C:\windows\system32\DRIVERS\battc.sys 6.3.9600.16384 (winblue_rtm.130821-1623)
来源:https://stackoverflow.com/questions/31170845/powershell-find-driver-version