Powershell: Add tab completion for -Scope parameters

Created on 23 Oct 2018  路  10Comments  路  Source: PowerShell/PowerShell

While pestering around on one of my personal modules, I noticed that the scope parameter on Cmdlets like Get-Alias, Set-Variable is not Validated. It's just... open. Don't we have defined scopes, like "Local", "Script", "Global", "Private" and _the numbers_? In fact, after examining the Pester tests included in _Powershell/test_, those are the only _valid_ values tested, and only up to scope 1. Who uses more than scope 2 anyway?? I'm going to rant and spitball here, so please bare with me.

Can we tag a ValidateSet attribute onto these parameters without breaking the intent of -Scope?

Seasoned users _know_ the scopes. And if we forget, I think we know to Get-Help about_Scopes. But new users may not, and with the amazing discoverability PowerShell has built-in, they may see they can set scopes on their variables and aliases. But, what scopes they can define aren't immediately available to them in the terminal. With tab completion set from a validation, that's remedied.

The only issue I see is: Where's the limit on numbered scopes? How to we get them? Are the scopes defined by the session state so if you enter in a scope 3 when you only have a scope 2, do you get a null or an exception? How high do we go and still have a valid scope integer? If there _is_ a limit that is determined by the session or stored in the ps session state, could we shift -Scope to be a Dynamic Parameter that pulls it's allowable values from "the list" and from the "current allowable numbered" scopes?

My current solution is to add tab completions for scope parameters. It will cycle through the list, and if I want to change it to a number, I can. They aren't used much anyway. This may be a big ol'nothingburger but I had to ask.

Area-Cmdlets-Utility Committee-Reviewed Hacktoberfest Issue-Enhancement Up-for-Grabs

Most helpful comment

We should probably have a custom validator to check that it's either an integer value or a named scope.

All 10 comments

We could add a completer (not ValidateSet).

We should probably have a custom validator to check that it's either an integer value or a named scope.

@iSazonov A completer is my current solution. It works just fine. But, if a user really wants to put Some-Cmdlet -Scope Bork, they still can and the command will, well, bork. I don't know if that's an issue or not.

@vexx32 Are you speaking of a custom class derived from ValidateArgumentsAttribute? ...that seems easier than a dynamic validation and digging through the instance for scopes.

@endowdly yes, indeed. You could easily model off of ValidateSet and do something like that, except if it doesn't match any of the existing named scopes it will still accept it if it's an integer. :)

I only see a value for UX with the completer. If an user do wrong input the user will get the same error message in both cases - without validateset and with one.

So I've been working on the Validator Attribute. It seems to work okay in testing so far, but I haven't had a lot of time with it. I really like this as a solution as it adds functionality to PowerShell that users can apply to their scripts. Are you building a cmdlet and want a -Scope parameter, where validation is kind of important? This can definitely help with that. Just throw a [ValidateScope()] attribute on it and continue on.

For now, I use TabExpansionPlusPlus and this completer:

$ScopeCompleter = {
    param ($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)

    "Local", "Script", "Global" | ForEach-Object { New-CompletionResult $_ }
}
$ScopeCompleterArgs = @{
    CommandName = (Get-CommandWithParameter -ParameterName Scope)
    ParameterName = "Scope"
    ScriptBlock = $ScopeCompleter
}

Register-ArgumentCompleter @ScopeCompleterArgs

Validated scope parameters, like on Install-Module do not get overwritten by this.

_Update_

I just realized the base TabExpansionPlusPlus _already_ includes the Scope parameter expansion (wicked smart, Jason). I never included Jason's original completers, which upon review, should be a 15 yard penalty. So just importing the full TabExpansionPlusPlus solves this problem, no need to include my completer. Use it though, if you don't want to add TabExpansionPlusPlus, just be sure to swap out the New-CompletionResult line with a proper [System.Management.Automation.CompletionResult] object.

To get a progress we should get PowerShell Committee approvement for new public API - ValidateScope vs CompleterScope.

/cc @SteveL-MSFT

So I have been learning lot about Scopes and here is a bit of clarification.

Scope Levels Limits
Currently the available scope levels numbers 0-2147483647
If the scope is a number above where global exists it will kick back an error which is why scoping seems to be such a confusing beast.

That being said. As far as a Validator is concerned I am not really certain why we would need a validator for this instead of using a custom ValidateScript because scope validation is still done at the scope level when you pass parameters through.

function Foo
{
    param(
        [ValidateScript({
            if ([Enum]::GetValues([System.Management.Automation.ScopedItemOptions]) -contains $_ ) {
                return $true
            }
            try {
                if (([int]$_ -ge 0) -and ([int]$_ -le [int]::MaxValue)) {
                    return $true
                }
            }
            catch { }
            throw "Invalid Scope of $_"
        })]
        [String]
        $Scope
    )
}

I understand we all want tab completion however I feel like having 2147483647+ Potential tab completions would slow down tab completion drastically where performance factors will be in play.

However I believe a ValidateSetAttribute would be great here if it allowed for Type Information as well.

Example:
[ValidateSet("Global","Script","Private","Local", [int]) ]

@romero126

The numbered scopes isn't an issue for tab completion, and there is no easy way to determine _which_ of the number is a valid scope. I mean there is, if you dig through the call stack, but that just seems like a folly. So the tab completion comes down to 4 real choices, and as I mention above, Jason Shirk's TabExpansionPlusPlus module adds completer for _every_ command that uses a -Scope parameter (see here if you want to do it yourself for some reason).

Your ValidateScript solution is _fine_ for a one-off script and for a _single user_. I'm talking about a _systematic_ ... issue? I still don't necessarily think it's an issue nor an oversight. At this point, I guess I'm talking about an additional feature.

Like I mentioned above, A ValidateScope attribute just makes it easy for validating these scopes for anyone, PowerShell wide.

Here is a Gist of my ValidateScopeAttribute I've been toying with to see what I'm talking about.

@PowerShell/powershell-committee reviewed this and agree to support tab completion for scopes

Was this page helpful?
0 / 5 - 0 ratings