Get-UnknownDevices.ps1


Description

@GitHub Copilot - Welcome @BanterBoy, I’m your Copilot and I’m here to help you get things done faster. I can identify issues, explain and even improve code.

You can ask generic questions, but what I’m really good at is helping you with your code. For example:

Generate unit tests for my code Explain the selected code Propose a fix for the bugs in my code If you want to learn more about my capabilities and limitations, check out the Copilot documentation.

I’m powered by AI, so surprises and mistakes are possible. Make sure to verify any generated code or suggestions, and share feedback so that we can learn and improve.

@BanterBoy: - Explain what the script does and why it is useful.

@GitHub Copilot -


Script

<#
.Synopsis
   When building a new system image for MDT or SCCM, it is common to need to lay down a new OS image and troubleshoot missing drivers.  This tool simplifies detemining what device is really meant by 'Unknown Device' in the Device Manager
.DESCRIPTION
   Based off of this great post by Johan Arwidmark of Deployment Research, this cmdlet can be used on a new system to help locate the names and IDs of device drivers.  The Cmdlet can be used without parameters, which will return a listing of all the devices with missing drivers.  Or, it can be run on a machine without web acess, using -Export to export a file.  The file should then be copied to a machine with web access where the -Import param can be used to import this file
.INPUTS
   To determine drivers from a system without internet access, use the -Import switch to specify the path to an import.csv file
   To determine drivers for the local system, no input is needed
.OUTPUTs
   In regular mode, emits PowerShell objects, containing a VendorID, DeviceId, DevMgrName and LikelyName properties
   In -Export mode, creates a import.csv file which can be copied and uses on a remote machine to resolve drivers (as web access is needed)
.EXAMPLE
    .\Get-UnknownDevices.ps1

VendorID DeviceID DevMgrName                                                                LikelyName
-------- -------- ----------                                                                ----------
8086     1E2D     Intel(R) 7 Series/C216 Chipset Family USB Enhanced Host Controller - 1E2D Intel(R) 7 Series/C216 Chipset Family USB Enhanced Host Controll...
8086     1E26     Intel(R) 7 Series/C216 Chipset Family USB Enhanced Host Controller - 1E26 Intel(R) 7 Series/C216 Chipset Family USB Enhanced Host Controll...
1B21     1042     ASMedia USB 3.0 eXtensible Host Controller - 0.96 (Microsoft)             Asmedia ASM104x USB 3.0 Host Controller...
8086     1E31     Intel(R) USB 3.0 eXtensible Host Controller - 1.0 (Microsoft)
1B21     1042     ASMedia USB 3.0 eXtensible Host Controller - 0.96 (Microsoft)             Asmedia ASM104x USB 3.0 Host Controller...

In this case, the cmdlet was run without any parameters which returns a list of any missing drivers and the likely source file, according to the PCIDatabase
.EXAMPLE
   .\Get-UnknownDevices.ps1 -Export C:\temp\DriverExport.csv

    >Export file created at C:\temp\DriverExport.csv, please copy to a machine with web access, and rerun this tool, using the -Import flag
.EXAMPLE
    .\Get-UnknownDevices.ps1 -Import C:\temp\DriverExport.csv

VendorID DeviceID DevMgrName                         LikelyName
-------- -------- ----------                         ----------
1186     4300     DGE-530T Gigabit Ethernet Adapter. Used on DGE-528T Gigabit adapt...
.LINK
   Copy and paste any of the links below for more information about this cmdlet
   start http://www.Foxdeploy.com
   start http://deploymentresearch.com/Research/Post/306/Back-to-basics-Finding-Lenovo-drivers-and-certify-hardware-control-freak-style
#>
Function Get-UnknownDevices{
[CmdletBinding()]
Param([ValidateScript({test-path (Split-Path $path)})]$Export,
      [ValidateScript({test-path $path})]$Import,
      [ValidateScript({test-path $path})]$Cab,
      [switch]$test)
begin {
        $i = 0

        if ($Import){
            $devices = Import-Csv $import
            }
            else {

            if ($Test){
                #For Testing, pull all devices
                $devices = Get-WmiObject Win32_PNPEntity | Where-Object{$_.ConfigManagerErrorCode -eq 0} | Select Name, DeviceID
                #For testing, I'm purposefully pulling Ethernet drivers
                $unknown_Dev = $devices | where Name -like "*int*"
                }
                else{
                    #if not running in -Test
                    #For Prod, Query WMI and get all of the devices with missing drivers
                    $devices = Get-WmiObject Win32_PNPEntity | Where-Object{$_.ConfigManagerErrorCode -ne 0} | Select Name, DeviceID
                    #For production
                    $unknown_Dev = $devices
                }
        }





        if ($Export){
            $unknown_Dev | export-csv $Export
            Write-host "Export file created at $Export, please copy to a machine with web access, and rerun this tool, using the -Import flag"
            BREAK
            }




        $unknown_Dev | % {$i++}
        $count = $i

        Write-verbose "$i unknown devices found on $env:COMPUTERNAME"
        If ($VerbosePreference -eq 'Continue'){
            $unknown_Dev | Format-Table}


        $FoldersToImport = new-object System.Collections.ArrayList
}


process{
        forEach ($device in $unknown_Dev){
            Write-Debug "to test the current `$device, $($device.Name), stop here"

            #Pull out specific values for VendorID and DeviceID, from the objects in $Unknown_dev
            $vendorID = ($device.DeviceID | Select-String -Pattern 'VEN_....' | select -expand Matches | select -expand Value) -replace 'VEN_',''
            $deviceID = ($device.DeviceID | Select-String -Pattern 'DEV_....' | select -expand Matches | select -expand Value) -replace 'DEV_',''

            if ($deviceID.Length -eq 0){
                Write-Verbose "found a null device, skipping..."
                Continue}

            if ($cab){
            #need to filter to include only those with matching $vendorId too
            $path = get-childitem $cabpath -recurse -include "*.inf" | select-string -pattern "ControlFlags" | gci | select-string $deviceID -list| gci | select-string -pattern $VendorID -list | Tee-Object -Variable Driver |  % {split-path $_.Path -Parent }

            $path | select -unique | ForEach {$FoldersToImport.add($_) | out-null}

            #drivers / folders
            [pscustomobject]@{Device=$device.Name;
                    DriverFiles=($driver.Filename |Select -unique) -join ',';
                    DriverFolders=($path | select -unique )-join "`n"}
            #"The drivers for the device $($device.Name) appear to be $($driver.Filename -join ',') which are found in this dir: $path"
            Continue
            }

            Write-Verbose "Searching for devices with Vendor ID of $vendorID and Device ID of $deviceID "

            $url = "http://www.pcidatabase.com/search.php?device_search_str=$deviceID&device_search=Search"
            try {$res = Invoke-WebRequest $url -UserAgent InternetExplorer}
         catch [System.NotSupportedException]{Write-warning "You need to launch Internet Explorer once before running this";return}

            $matches = ($res.ParsedHtml.getElementsByTagName('p') | select -expand innerHtml).Split()[1]
            Write-Verbose "Found $matches matches"

            $htmlCells = $res.ParsedHtml.getElementsByTagName('tr')  | select -skip 4 -Property *html*
            Write-Debug "test `$htmlCells for the right values $htmlCells"

            #
            $matchingDev = ($htmlCells.InnerHtml | Select-String -Pattern $vendorID | select -expand Line).ToString().Split("`n")
            if ($matchingDev.count -ge 1){
                    [pscustomobject]@{VendorID=$vendorID;DeviceID=$deviceID;DevMgrName=$device.Name;LikelyName=$matchingDev[1] -replace '<TD>','' -replace '</TD>',''}}
                else{CONTINUE}

                }
}
end{

    "To enable all of the unknown devices on your system, import drivers from these paths"
    $FoldersToImport | select -Unique
}
}

<#
To do :

Add parameter sets, where -CAB forces the user to specify a Cab path

add support for unzipping actual cabs files

rewrite help docs

#>


<#
#experiemental weird stuff below

#Finds infs with matching device IDs
get-childitem $cabpath -recurse -include "*.inf" | select-string -pattern $deviceID -list| select Path

#need to filter to include only those with matching $vendorId too
$path = get-childitem $cabpath -recurse -include "*.inf" | select-string -pattern "ControlFlags" | gci | select-string $deviceID -list| gci | select-string -pattern $VendorID -list | Tee-Object -Variable Driver |  % {split-path $_.Path -Parent }

#drivers / folders

"The drivers for the device $($device.Name) appear to be $($driver.Filename -join ',') which are found in this dir: $path"
#>

Back to Top


Download

Please feel free to copy parts of the script or if you would like to download the entire script, simple click the download button. You can download the complete repository in a zip file by clicking the Download link in the menu bar on the left hand side of the page.


Report Issues

You can report an issue or contribute to this site on GitHub. Simply click the button below and add any relevant notes. I will attempt to respond to all issues as soon as possible.

Issue


Back to Top