Created
September 4, 2025 16:35
-
-
Save BradKnowles/14ed0a263112a571e26d070d07b58e4e to your computer and use it in GitHub Desktop.
AI Generated PowerShell function to list argument completers and their associated script blocks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function Get-ArgumentCompleters { | |
| <# | |
| .SYNOPSIS | |
| Lists all registered argument completers created with Register-ArgumentCompleter. | |
| .DESCRIPTION | |
| This function retrieves all custom argument completers registered in the current PowerShell session | |
| using Register-ArgumentCompleter and displays their script block contents. | |
| .PARAMETER ShowScriptBlock | |
| If specified, displays the full script block content in a readable format. | |
| .EXAMPLE | |
| Get-ArgumentCompleters | |
| Lists all registered argument completers. | |
| .EXAMPLE | |
| Get-ArgumentCompleters -ShowScriptBlock | |
| Lists all registered argument completers with full script block content. | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [switch]$ShowScriptBlock | |
| ) | |
| try { | |
| $completers = @() | |
| # Access the internal ExecutionContext to get to the CommandDiscovery | |
| $contextField = $ExecutionContext.GetType().GetField('_context', [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance) | |
| if (-not $contextField) { | |
| throw "Could not access ExecutionContext._context field" | |
| } | |
| $internalContext = $contextField.GetValue($ExecutionContext) | |
| if (-not $internalContext) { | |
| throw "Could not get internal ExecutionContext" | |
| } | |
| # Get the AutomationEngine | |
| $engineField = $internalContext.GetType().GetField('<Engine>k__BackingField', [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance) | |
| if (-not $engineField) { | |
| throw "Could not access Engine field" | |
| } | |
| $automationEngine = $engineField.GetValue($internalContext) | |
| if (-not $automationEngine) { | |
| throw "Could not get AutomationEngine" | |
| } | |
| # Get the CommandDiscovery | |
| $commandDiscoveryField = $automationEngine.GetType().GetField('<CommandDiscovery>k__BackingField', [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance) | |
| if (-not $commandDiscoveryField) { | |
| throw "Could not access CommandDiscovery field" | |
| } | |
| $commandDiscovery = $commandDiscoveryField.GetValue($automationEngine) | |
| if (-not $commandDiscovery) { | |
| throw "Could not get CommandDiscovery" | |
| } | |
| # Look for argument completer storage in CommandDiscovery | |
| $discoveryFields = $commandDiscovery.GetType().GetFields([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Public) | |
| foreach ($field in $discoveryFields) { | |
| try { | |
| $value = $field.GetValue($commandDiscovery) | |
| if ($value -ne $null -and $value.GetType().Name -like "*Dictionary*") { | |
| # Check if this dictionary contains script blocks (likely completers) | |
| foreach ($kvp in $value.GetEnumerator()) { | |
| if ($kvp.Value -and $kvp.Value.GetType().Name -eq "ScriptBlock") { | |
| $completers += [PSCustomObject]@{ | |
| CommandName = $kvp.Key | |
| CompleterSource = "CommandDiscovery.$($field.Name)" | |
| ScriptBlock = if ($ShowScriptBlock) { $kvp.Value.ToString() } else { $kvp.Value.ToString().Substring(0, [Math]::Min(100, $kvp.Value.ToString().Length)) + "..." } | |
| FullScriptBlock = $kvp.Value | |
| } | |
| } | |
| } | |
| } | |
| } | |
| catch { | |
| # Ignore fields we can't access | |
| continue | |
| } | |
| } | |
| # If we didn't find completers in CommandDiscovery, try looking in the execution context itself | |
| if ($completers.Count -eq 0) { | |
| $contextFields = $internalContext.GetType().GetFields([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Public) | |
| foreach ($field in $contextFields) { | |
| try { | |
| $value = $field.GetValue($internalContext) | |
| if ($value -ne $null -and $value.GetType().Name -like "*Dictionary*") { | |
| foreach ($kvp in $value.GetEnumerator()) { | |
| if ($kvp.Value -and $kvp.Value.GetType().Name -eq "ScriptBlock") { | |
| $completers += [PSCustomObject]@{ | |
| CommandName = $kvp.Key | |
| CompleterSource = "ExecutionContext.$($field.Name)" | |
| ScriptBlock = if ($ShowScriptBlock) { $kvp.Value.ToString() } else { $kvp.Value.ToString().Substring(0, [Math]::Min(100, $kvp.Value.ToString().Length)) + "..." } | |
| FullScriptBlock = $kvp.Value | |
| } | |
| } | |
| } | |
| } | |
| } | |
| catch { | |
| continue | |
| } | |
| } | |
| } | |
| # Return results | |
| if ($completers.Count -gt 0) { | |
| $result = $completers | Sort-Object CommandName | |
| if ($ShowScriptBlock) { | |
| foreach ($completer in $result) { | |
| Write-Host "`n=== $($completer.CommandName) ===" -ForegroundColor Green | |
| Write-Host "Source: $($completer.CompleterSource)" -ForegroundColor Yellow | |
| Write-Host "Script Block:" -ForegroundColor Cyan | |
| Write-Host $completer.FullScriptBlock.ToString() -ForegroundColor White | |
| Write-Host ("-" * 50) -ForegroundColor Gray | |
| } | |
| } else { | |
| $result | Select-Object CommandName, CompleterSource, ScriptBlock | |
| } | |
| } else { | |
| Write-Warning "No argument completers found in the current session." | |
| Write-Host "`nThis could be because:" -ForegroundColor Yellow | |
| Write-Host " 1. No completers have been registered with Register-ArgumentCompleter" -ForegroundColor Cyan | |
| Write-Host " 2. The internal storage mechanism has changed in this PowerShell version" -ForegroundColor Cyan | |
| Write-Host " 3. Completers are stored in a location not yet discovered by this function" -ForegroundColor Cyan | |
| Write-Host "`nTo register a new completer, use:" -ForegroundColor Yellow | |
| Write-Host "Register-ArgumentCompleter -CommandName 'YourCommand' -ScriptBlock { param(`$commandName, `$parameterName, `$wordToComplete, `$commandAst, `$fakeBoundParameter) }" -ForegroundColor Cyan | |
| } | |
| } | |
| catch { | |
| Write-Error "Failed to retrieve argument completers: $($_.Exception.Message)" | |
| Write-Host "`nThis error suggests the internal PowerShell structure may have changed." -ForegroundColor Yellow | |
| Write-Host "Please report this issue with your PowerShell version: $($PSVersionTable.PSVersion)" -ForegroundColor Cyan | |
| } | |
| } | |
| # Remove the Export-ModuleMember since this is a script, not a module |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment