Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rohnedwards/1a78c57936d773f2a541d7ac3124f921 to your computer and use it in GitHub Desktop.
Save rohnedwards/1a78c57936d773f2a541d7ac3124f921 to your computer and use it in GitHub Desktop.
Example of ArgumentCompleter looking back in Command AST
# See here for question: https://rohnspowershellblog.wordpress.com/2017/01/17/completing-parameter-values-with-other-parameter-values/#comment-437
function Test-DetectProperty {
<#
.SYNOPSIS
Proof of concept to show that inspecting preceding command elements is possible
from within ArgumentCompleters, at least in a limited way.
.EXAMPLE
Get-Service | Test-DetectProperty -Property <PressTab>
.EXAMPLE
$Services = Get-Service
$Services | Test-DetectProperty -Property <PressTab>
# Note that this won't work b/c we we don't handle the particular AST type:
$Services[0] | Test-DetectProperty -Property <PressTab>
# This won't work either, b/c there are two commands you'd have to walk back:
$Services | Select-Object -First 1 | Test-DetectProperty -Property <PressTab>
# This will, though:
$SingleService = $Services | Select-Object -First 1
$SingleService | Test-DetectProperty -Property <PressTab>
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline)]
$InputObject,
[ArgumentCompleter({
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
$Pipeline = $commandAst.Parent
$PrecedingElement = $null
$FoundPrecedingElement = $fase
foreach ($Element in $Pipeline.PipelineElements) {
if ($Element -eq $commandAst) {
$FoundPrecedingElement = $true
break
}
$PrecedingElement = $Element
}
if (-not $FoundPrecedingElement) {
$PrecedingElement = $null
}
$Properties = if ($PrecedingElement) {
switch ($PrecedingElement.GetType().Name) {
CommandAst { # Another command
$PrevCommandName = $PrecedingElement.CommandElements[0].ToString()
$CmdInfo = Get-Command $PrevCommandName -ErrorAction SilentlyContinue
if ($CmdInfo.OutputType) {
$CmdInfo.OutputType.Type.GetProperties().Name | Sort-Object -Unique
}
}
CommandExpressionAst { # Expression
if ($PrecedingElement.Expression.GetType().Name -eq 'VariableExpressionAst') {
$PrecedingVar = Get-Variable $PrecedingElement.Expression.VariablePath.ToString() -ErrorAction SilentlyContinue -ValueOnly
if ($PrecedingVar) {
$PrecedingVar | Get-Member | ForEach-Object Name
}
}
}
}
}
if ($Properties) {
$Properties.ForEach{
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}
})]
[string[]] $Property
)
process {
$PSBoundParameters
}
}
@B4Art
Copy link

B4Art commented Jan 22, 2021

Very Nice

If you change:

    $PrecedingVar | Get-Member | ForEach-Object Name

Into:

   $PrecedingVar | Get-Member -MemberType NoteProperty | ForEach-Object Name

You get only the NotePropertyNames

Realy handy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment