5

First, I do apologize for posting another question concerning PowerShell and tab completion. The StackOverflow system identified several excellent questions with answers concerning this very topic, but they all seemed too cumbersome to implement into this simple New-ADComputer script.

The params are going into a Splat to keep the script readable. The following code correctly tab completes in the ISE, but must be wrapped in double quotes.

Is there any native method in PowerShell to allow for tab completion of Parameter Sets that include spaces?

Param(
  [Parameter(Mandatory=$true)]
  [string]$Server,
  [Parameter(Mandatory=$true)]
  [ValidateSet('Env1','Env 2','Env 3')]
  [string]$Environment,
  [Parameter(Mandatory=$true)]
  [ValidateSet('Application','Database','File and Print','Web Server')]
  [string]$Type
)
$NewADitems = @{
  Name        = $server
  Path        = "OU=$Type,OU=$Environment,OU=Smaller DN string"
  Location    ='MySite'
  Description = "Test Description"
  ManagedBy   = "Huge Distingushed Name string"
  WhatIf      = $true
}
Write-Host @NewADitems

Command used and error received:

PS C:\Scripts> .\ADComputer-ParamTest.ps1 -Server ThisTest -Environment Env 3 -Type File and Print
C:\Scripts\ADComputer-ParamTest.ps1 : Cannot validate argument on parameter
'Environment'. The argument "Env" does not belong to the set "Env1,Env 2,Env3"
specified by the ValidateSet attribute. Supply an argument that is in the
set and then try the command again.At line:1 char:58
+ .\ADComputer-ParamTest.ps1 -Server ThisTest -Environment Env 3 -Type File and Pr ...
+                                                          ~~~

Edit: More information. If you leave off the single/double quotes in my example script for the parameter Environment, tab completion will not work for the final parameter Type. Enclosing the 2nd set in quotes will correct this but it's a way to keep watch for this behavior.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
user4317867
  • 2,397
  • 4
  • 31
  • 57
  • The quoting requirements are pretty strict and probably the most relevant to the tab completion issue. May I suggest limiting the scope of this question to the tab completion? I think it's different enough to keep isolated. It's shown me new things about tab completions with spaces which I thought would be impossible. Breaking the New-ADComputer splatting question into a separate question would probably bring more views/answers. – Booga Roo Jun 04 '15 at 04:44
  • P.S. it might help to include a link to this original question to show the relevant code and troubleshooting already done. I'd love to see this question answered with something solid that works to solve the issue. – Booga Roo Jun 04 '15 at 04:55
  • Fair point, every search I've done for New-ADComputer and splatting end up here!!! I'm guessing this script will need two functions, the first to start the tab completion string and that's passed to a 2nd function with a switch param that will allow for a space then perform the work. – user4317867 Jun 04 '15 at 06:30

2 Answers2

2

No, at least up to Powershell 5.0 April 2015 preview. Tab completion works as you describe. It will still need the quotes around the set to actually work without throwing the error. For what it's worth, it does add the closing quote of the matching type when you start the tab completion with a quote. For example, pressing "f then Tab will complete to "File and Print"(not sure when that was added as a feature).

I tried finding ways to auto-include the quotes as part of the ValidateSet including additional double quotes around the parameter sets and other attempts at escaping quotes. All attempts resulted in tab completion not working in various ways.

Some of the attempts, in case anyone might try that avenue:

[ValidateSet('Env1','"Env 2"','"Env 3"')]
[ValidateSet('Env1',"'Env 2'","'Env 3'")]
[ValidateSet('Env1','`"Env 2`"',"`'Env 3`'")]
[ValidateSet('Env1','\"Env 2\"',"\'Env 3\'")]
Booga Roo
  • 1,665
  • 1
  • 21
  • 30
  • 1
    Ran into that as well, enclosing the sets in double quotes and single quotes results in the string being quoted after tab completion but still causes weird issues. I also note there is some add-ons from a Powershell developer but I'm aiming to keep this script as barebones simple as possible. – user4317867 Jun 04 '15 at 02:05
  • I ran into this, http://stackoverflow.com/questions/22129621/powershell-pass-function-as-a-parameter, haven't had time to try working with this but it might be helpful – user4317867 Jun 04 '15 at 06:46
2

This has been entered as a bug since 2013. According to the workarounds listed in Auto-completed parameter values, with spaces, do not have quotes around them, you can update the TabExpansion2 function that Powershell uses for autocompletion. To do so, just run the following code:

function TabExpansion2
{
    [CmdletBinding(DefaultParameterSetName = 'ScriptInputSet')]
    Param(
        [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 0)]
        [string] $inputScript,

        [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 1)]
        [int] $cursorColumn,

        [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 0)]
        [System.Management.Automation.Language.Ast] $ast,

        [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 1)]
        [System.Management.Automation.Language.Token[]] $tokens,

        [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 2)]
        [System.Management.Automation.Language.IScriptPosition] $positionOfCursor,

        [Parameter(ParameterSetName = 'ScriptInputSet', Position = 2)]
        [Parameter(ParameterSetName = 'AstInputSet', Position = 3)]
        [Hashtable] $options = $null
    )

    End
    {
        if ($psCmdlet.ParameterSetName -eq 'ScriptInputSet')
        {
            $completion = [System.Management.Automation.CommandCompletion]::CompleteInput(
                $inputScript,
                $cursorColumn,
                $options)
        }
        else
        {
            $completion = [System.Management.Automation.CommandCompletion]::CompleteInput(
                $ast,
                $tokens,
                $positionOfCursor,
                $options)
        }

        $count = $completion.CompletionMatches.Count
        for ($i = 0; $i -lt $count; $i++)
        {
            $result = $completion.CompletionMatches[$i]

            if ($result.CompletionText -match '\s')
            {
                $completion.CompletionMatches[$i] = New-Object System.Management.Automation.CompletionResult(
                    "'$($result.CompletionText)'",
                    $result.ListItemText,
                    $result.ResultType,
                    $result.ToolTip
                )
            }
        }

        return $completion
    }
}

It's worth noting that string insertion works properly for native cmdlets like Get-EventLog -LogName which will properly encase 'Internet Explorer'. Although if you look at the source for Get-EventLog, you'll see that $LogName doesn't actually use ValidateSet so it's intellisense must be provided through another mechanism.


Other Instances:

Community
  • 1
  • 1
KyleMit
  • 30,350
  • 66
  • 462
  • 664