Public/Get-ConnectedPsGadget.ps1
|
#Requires -Version 5.1 # Get-ConnectedPsGadget.ps1 # Lists all PsGadgetFtdi instances currently held in session variables. function Get-ConnectedPsGadget { <# .SYNOPSIS Lists all PsGadgetFtdi objects currently held in session variables. .DESCRIPTION Scans all variables in the global scope for PsGadgetFtdi instances and returns a summary showing the variable name, serial number, device type, GPIO method, and open state. Each unique connection object appears exactly once. If multiple variables reference the same object (aliases), the first variable name is shown in Variable and the rest appear in Aliases. Arrays and hashtables containing PsGadgetFtdi instances are also scanned. .PARAMETER IncludeClosed Include PsGadgetFtdi instances where IsOpen = False. By default only open devices are returned. .EXAMPLE Get-ConnectedPsGadget .EXAMPLE # Include stale closed handles Get-ConnectedPsGadget -IncludeClosed .OUTPUTS PSCustomObject with Variable, Aliases, SerialNumber, Type, GpioMethod, IsOpen. #> [CmdletBinding()] [OutputType([System.Object[]])] param( [switch]$IncludeClosed ) # Phase 1: harvest all (label, object) pairs from global scope. # Multiple variables may alias the same underlying object instance. $candidates = [System.Collections.Generic.List[PSCustomObject]]::new() foreach ($var in (Get-Variable -Scope Global -ErrorAction SilentlyContinue)) { $val = $var.Value if ($null -eq $val) { continue } # Direct PsGadgetFtdi variable if ($val -is [PsGadgetFtdi]) { $candidates.Add([PSCustomObject]@{ Label = "`$$($var.Name)"; Obj = $val }) continue } # Array containing PsGadgetFtdi instances if ($val -is [System.Collections.IEnumerable] -and $val -isnot [string]) { try { $idx = 0 foreach ($item in $val) { if ($item -is [PsGadgetFtdi]) { $candidates.Add([PSCustomObject]@{ Label = "`$$($var.Name)[$idx]"; Obj = $item }) } $idx++ } } catch { } continue } # Hashtable containing PsGadgetFtdi instances if ($val -is [System.Collections.IDictionary]) { try { foreach ($key in $val.Keys) { $item = $val[$key] if ($item -is [PsGadgetFtdi]) { $candidates.Add([PSCustomObject]@{ Label = "`$$($var.Name)['$key']"; Obj = $item }) } } } catch { } } } # Phase 2: deduplicate by object identity. # Group all variable labels that alias the same underlying object instance. $uniqueObjects = [System.Collections.Generic.List[object]]::new() $uniqueLabels = [System.Collections.Generic.List[System.Collections.Generic.List[string]]]::new() foreach ($c in $candidates) { $found = $false for ($i = 0; $i -lt $uniqueObjects.Count; $i++) { if ([object]::ReferenceEquals($uniqueObjects[$i], $c.Obj)) { $uniqueLabels[$i].Add($c.Label) $found = $true break } } if (-not $found) { $uniqueObjects.Add($c.Obj) $labelList = [System.Collections.Generic.List[string]]::new() $labelList.Add($c.Label) $uniqueLabels.Add($labelList) } } # Phase 3: build results -- one row per unique object, filtered by IsOpen. $results = [System.Collections.Generic.List[PSCustomObject]]::new() for ($i = 0; $i -lt $uniqueObjects.Count; $i++) { $obj = $uniqueObjects[$i] $labels = $uniqueLabels[$i] if (-not $IncludeClosed -and -not $obj.IsOpen) { continue } $results.Add([PSCustomObject]@{ Variable = $labels[0] Aliases = if ($labels.Count -gt 1) { ($labels | Select-Object -Skip 1) -join ', ' } else { '' } SerialNumber = $obj.SerialNumber Type = $obj.Type GpioMethod = $obj.GpioMethod IsOpen = $obj.IsOpen }) } if ($results.Count -eq 0 -and -not $IncludeClosed) { Write-Verbose "No open PsGadgetFtdi devices found. Use -IncludeClosed to include closed handles." } return $results.ToArray() } |