The following solution uses a parameter-specific [ArgumentCompleter()]
attribute as part of the definition of the Get-Property
function itself, but the solution analogously applies to separately defining custom-completion logic via the Register-CommandCompleter
cmdlet.
Limitations:
The custom-completion script block ({ ... }
) invoked by PowerShell fundamentally only sees values specified via parameters, not via the pipeline.
- That is, if you type
Get-Property -Object $obj -Property <tab>
, the script block can determine that the value of $obj
is to be bound to the -Object
parameter, but that wouldn't work with
$obj | Get-Property -Property <tab>
(even if -Object
is declared as pipeline-binding).
Even among those values specified via parameters, only values that can be evaluated without side effects are actually accessible in the script block; in concrete this terms, this means:
- Literal values (e.g.,
-Object ([pscustomobject] @{ foo = 1; bar = 2; baz = 3 })
- Simple variable references (e.g.,
-Object $obj
) or property-access or index-access expressions (e.g., -Object $obj.Foo
or -Object $obj[0]
)
- Notably, the following values are not accessible:
- Method-call results (e.g.,
-Object $object.Foo()
)
- Command output (via
(...)
, $(...)
, or @(...)
, e.g.
-Object (Invoke-RestMethod http://example.org)
)
- The reason for this limitation is that evaluating such values before actually submitting the command could have undesirable side effects and / or could take a long time to complete.
function Get-Property {
param(
[object] $Object,
[ArgumentCompleter({
# A fixed list of parameters is passed to an argument-completer script block.
# Here, only two are of interest:
# * $wordToComplete:
# The part of the value that the user has typed so far, if any.
# * $preBoundParameters (called $fakeBoundParameters
# in the docs):
# A hashtable of those (future) parameter values specified so
# far that are side effect-free (see above).
param($cmdName, $paramName, $wordToComplete, $cmdAst, $preBoundParameters)
# Was a side effect-free value specified for -Object?
if ($obj = $preBoundParameters['Object']) {
# Get all property names of the objects and filter them
# by the partial value already typed, if any,
# interpreted as a name prefix.
@($obj.psobject.Properties.Name) -like "$wordToComplete*"
}
})]
[string] $Property
)
# ...
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…