public/Get-UsbDevices.ps1
|
function Get-USBDevices { <# .SYNOPSIS Get a list of USB devices. .DESCRIPTION Get a list of USB devices. This function uses the `lsusb` command to retrieve information about connected USB devices and organizes it into a structured format. .PARAMETER ShowVerbose Whether to show verbose output during processing. .EXAMPLE Get-USBDevices Returns a list of connected USB devices with their details. .EXAMPLE Get-USBDevices -ShowVerbose Returns a list of connected USB devices with verbose output during processing. .LINK https://github.com/Skatterbrainz/linuxtools/blob/master/docs/Get-USBDevices.md #> [CmdletBinding()] param ( [parameter(Mandatory=$false)][switch]$ShowVerbose ) lsusb -v 2>/dev/null | ForEach-Object -Begin { $devices = @() $current = $null $currentConfig = $null $currentInterface = $null $currentEndpoint = $null } -Process { if ($_ -match '^Bus (\d+) Device (\d+): ID ([0-9a-f]{4}):([0-9a-f]{4}) (.+)$') { if ($current) { $devices += $current } $current = [PSCustomObject]@{ Bus = $matches[1] Device = $matches[2] VendorID = $matches[3] ProductID = $matches[4] Description = $matches[5].Trim() Configurations = [System.Collections.ArrayList]@() } $currentConfig = $null; $currentInterface = $null; $currentEndpoint = $null } elseif ($_ -match '^Device Descriptor:$') { } elseif ($_ -match '^ Configuration Descriptor:$') { $currentConfig = [PSCustomObject]@{ Interfaces = [System.Collections.ArrayList]@() } [void]$current.Configurations.Add($currentConfig) $currentInterface = $null; $currentEndpoint = $null } elseif ($_ -match '^ Interface Descriptor:$') { $currentInterface = [PSCustomObject]@{ Endpoints = [System.Collections.ArrayList]@() } [void]$currentConfig.Interfaces.Add($currentInterface) $currentEndpoint = $null if ($ShowVerbose) { Write-Verbose "Found Interface Descriptor" } } elseif ($_ -match '^ Endpoint Descriptor:$') { $currentEndpoint = [PSCustomObject]@{} # Don't add to collection yet - wait until we have actual properties if ($ShowVerbose) { Write-Verbose "Found Endpoint Descriptor" } } elseif ($_ -match '^ (.+?):\s+(.+)$') { $key = $matches[1].Trim() -replace '[^\w]', '' $current | Add-Member -NotePropertyName $key -NotePropertyValue $matches[2].Trim() -Force } elseif ($_ -match '^ (.+?):\s+(.+)$' -and $currentConfig) { $key = $matches[1].Trim() -replace '[^\w]', '' $currentConfig | Add-Member -NotePropertyName $key -NotePropertyValue $matches[2].Trim() -Force } elseif ($_ -match '^ ([a-zA-Z][^:]*?)\s+(.+)$' -and $currentInterface -and $_ -notmatch 'Descriptor:$' -and $_ -notmatch '^ ') { $key = $matches[1].Trim() -replace '[^\w]', '' $value = $matches[2].Trim() if ($key -ne '') { $currentInterface | Add-Member -NotePropertyName $key -NotePropertyValue $value -Force if ($ShowVerbose) { Write-Verbose "Added Interface property: $key = $value" } } } elseif ($_ -match '^ ([a-zA-Z][^:]*?)\s+(.+)$' -and $currentEndpoint -and $_ -notmatch 'Descriptor:$' -and $_ -notmatch '^ ') { $key = $matches[1].Trim() -replace '[^\w]', '' $value = $matches[2].Trim() if ($key -ne '') { $currentEndpoint | Add-Member -NotePropertyName $key -NotePropertyValue $value -Force # Add endpoint to collection on first property (ensures it has content) if ($currentInterface.Endpoints -notcontains $currentEndpoint) { [void]$currentInterface.Endpoints.Add($currentEndpoint) } if ($ShowVerbose) { Write-Verbose "Added Endpoint property: $key = $value" } } } elseif ($_ -match '^ ([a-zA-Z][^:]*?)\s+(.+)$' -and $currentEndpoint) { # Handle nested endpoint properties (like Transfer Type, Synch Type, etc.) $key = $matches[1].Trim() -replace '[^\w]', '' $value = $matches[2].Trim() if ($key -ne '') { $currentEndpoint | Add-Member -NotePropertyName $key -NotePropertyValue $value -Force if ($ShowVerbose) { Write-Verbose "Added nested Endpoint property: $key = $value" } } } } -End { if ($current) { $devices += $current } # Convert ArrayLists to arrays for proper object structure foreach ($device in $devices) { if ($device.Configurations) { $device.Configurations = @($device.Configurations) foreach ($config in $device.Configurations) { if ($config.Interfaces) { # First, filter endpoints for each interface foreach ($interface in $config.Interfaces) { if ($interface.Endpoints) { # Filter out empty endpoints (those with no properties) $validEndpoints = @($interface.Endpoints | Where-Object { ($_ | Get-Member -MemberType NoteProperty).Count -gt 0 }) $interface.Endpoints = $validEndpoints } } # Keep all interfaces - they may have properties even without endpoints $config.Interfaces = @($config.Interfaces) } } } } $devices } } |