question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ValidateSet/Register-ArgumentCompleter/Enum completions does not work correctly

See original GitHub issue

Issue Description

I am experiencing a problem with… completions failing for 2nd entry.

ThisWayWeird

Notice that it works on 14th line, and then very same command fails on line 10th.

function Get-GPOZaurrPermissionSummary {
    [cmdletBinding()]
    param(
        [validateSet('AuthenticatedUsers', 'DomainComputers', 'Unknown', 'WellKnownAdministrative', 'NotWellKnown', 'NotWellKnownAdministrative', 'NotAdministrative', 'Administrative', 'All')][string[]] $Type = 'All',
        [validateSet('Allow', 'Deny', 'All')][string] $PermitType = 'All',
        [ValidateSet('GpoApply', 'GpoEdit', 'GpoCustom', 'GpoEditDeleteModifySecurity', 'GpoRead', 'GpoOwner', 'GpoCustomCreate', 'GpoCustomOwner')][string[]] $IncludePermissionType,
        [ValidateSet('GpoApply', 'GpoEdit', 'GpoCustom', 'GpoEditDeleteModifySecurity', 'GpoRead', 'GpoOwner', 'GpoCustomCreate', 'GpoCustomOwner')][string[]] $ExcludePermissionType,
        [Microsoft.GroupPolicy.GPPermissionType[]] $Test,

        [alias('ForestName')][string] $Forest,
        [string[]] $ExcludeDomains,
        [alias('Domain', 'Domains')][string[]] $IncludeDomains,
        [System.Collections.IDictionary] $ExtendedForestInformation,

        [string] $Separator
    )

I tried to replicate it to give you reproducible code but I just can’t. I’m experiencing it across all my modules and I can’t pinpoint it to what I’m doing wrong. It fails the same way for both [Microsoft.GroupPolicy.GPPermissionType[]] which is an enum, but also have the same issue with ValidateSet and Register-ArgumentCompleter that makes me want to cry 😃

Attached Logs

1601583262-5511c227-6bca-4824-9bad-6f29a894ed501601499246405.zip

Follow the instructions in the README about capturing and sending logs.

Environment Information

Visual Studio Code

Name Version
Operating System Windows_NT x64 10.0.19042
VSCode 1.49.2
PowerShell Extension Version 2020.9.0

PowerShell Information

Name Value
PSVersion 5.1.19041.541
PSEdition Desktop
PSCompatibleVersions 1.0 2.0 3.0 4.0 5.0 5.1.19041.541
BuildVersion 10.0.19041.541
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

Visual Studio Code Extensions

Visual Studio Code Extensions(Click to Expand)
Extension Author Version
better-toml bungcip 0.3.2
csharp ms-dotnettools 1.23.2
errorlens usernamehw 3.2.2
github-linker gimenete 0.2.3
gitlens eamodio 10.2.2
line-endings steditor 1.0.3
LogFileHighlighter emilast 2.9.0
markdown-all-in-one yzhang 3.3.0
material-icon-theme PKief 4.3.0
open-in-browser techer 2.0.0
powershell-preview ms-vscode 2020.9.0
project-manager alefragnani 11.3.0
rainbow-brackets 2gua 0.0.6
run-in-powershell tobysmith568 1.1.0
swdc-vscode softwaredotcom 2.3.12
vscode-markdownlint DavidAnson 0.37.0
vscode-toggle-quotes BriteSnow 0.3.3
vscode-wakatime WakaTime 4.0.8
vscode-yaml redhat 0.11.1
xml DotJoshJohnson 2.5.1

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:25 (12 by maintainers)

github_iconTop GitHub Comments

2reactions
SeeminglySciencecommented, Oct 9, 2020

Also here’s an editor command you can use to test if TabExpansion2 gives the same result:

Microsoft.VSCode_profile.ps1
Register-EditorCommand -DisplayName 'Show Engine Completion Results' -Name EditorTabExpansion2 -ScriptBlock {
    param(
        [Microsoft.PowerShell.EditorServices.Extensions.EditorContext, Microsoft.PowerShell.EditorServices]
        $Context
    )
    end {
        function GetLineMap {
            [OutputType([int[]])]
            param([string] $text)
            end {
                $lineStartMap = [System.Collections.Generic.List[int]]::new(100)
                $lineStartMap.Add(0)
                for ($i = 0; $i -lt $text.Length; ++$i) {
                    $c = $text[$i];
    
                    if ($c -eq "`r"[0]) {
                        if (($i + 1) -lt $text.Length -and $text[$i + 1] -eq "`n"[0]) {
                            $i++;
                        }
    
                        $lineStartMap.Add($i + 1)
                    }
    
                    if ($c -eq "`n") {
                        $lineStartMap.Add($i + 1);
                    }
                }
    
                return ,$lineStartMap.ToArray()
            }
        }

        $fileContext = $Context.CurrentFile
        $scriptAst = $fileContext.Ast
        $scriptTokens = $fileContext.Tokens

        $scriptText = $scriptAst.Extent.Text
        $lineStartMap = GetLineMap $scriptText
        $offset = ($lineStartMap[$Context.CursorPosition.Line - 1] + $Context.CursorPosition.Column) - 1
        $newPosition = $scriptAst.Extent.StartScriptPosition.GetType().
            GetMethod(
                <# name: #> 'CloneWithNewOffset',
                <# bindingAttr: #> [System.Reflection.BindingFlags]'NonPublic, Public, Instance',
                <# binder: #> $null,
                <# types: #> [type[]][int],
                <# modifiers: #> $null).
            Invoke($scriptAst.Extent.StartScriptPosition, @($offset))

        $completionMatches = [System.Management.Automation.CommandCompletion]::
            CompleteInput($scriptAst, $scriptTokens, $newPosition, @{}).
            CompletionMatches

        if (-not $completionMatches) {
            Write-Host
            Write-Host 'CompleteInput returned no matches.'
            return
        }

        $completionMatches | Out-Host
    }
}
keybindings.json
    {
        "key": "ctrl+shift+space",
        "command": "PowerShell.InvokeRegisteredEditorCommand",
        "args": { "commandName": "EditorTabExpansion2" },
        "when": "editorTextFocus && editorLangId == 'powershell'",
    },
1reaction
PrzemyslawKlyscommented, Oct 9, 2020

COol 😄 I will be using the comma workaround in near future.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Looping Register-ArgumentCompleter produces incorrect ...
The motivation here is that I can't directly set the module function's input parameters to autoconvert into the enum type (which would properly...
Read more >
Tab-completion of command based upon a folderlist?
If it is, it runs the Register-ArgumentCompleter command (3 times in this case). If it's not, it displays a warning (you could change...
Read more >
Argument Completion Attributes - powershell.one
Argument completion will not work in the script pane where the function was defined. It works only in the console and other open...
Read more >
The classy way to complete and validate PowerShell ...
Use the argument completer attribute with a PowerShell function or Class. If you won't target older versions. The function is probably more ...
Read more >
Using a Custom Enum To Get Tab-Completion on a Parameter
PowerShell already has support for doing this kind of thing via the ValidateSet parameter attribute. This attribute not only prevents users ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found