Skip to content

ValidateSet should support a dynamically generated set from a script block #8651

Description

@OlsonDev

Summary of the new feature/enhancement

As a PowerShell user, I want [ValidateSet] to support a dynamically generated sets from script blocks so that I can make terse, reusable sets of data, and my coworkers are provided useful IntelliSense from my work. In issue #3744, it was proposed to support a dynamically generated set for [ValidateSet]. An example was given with a script block, which would resolve the set. However, the actual merged PR laid the groundwork and implemented a variant, using classes and interfaces. I'd like this issue to specifically track the ability to use [ValidateSet] with a script block and receive IntelliSense feedback.

Proposed technical implementation details

For example:

[CmdletBinding()]
param (
    [ValidateSet({ (Get-MyGitRepos -Code -Config).master })]
    $Repo = "foo"
)

Activity

  1. vexx32 commented on Jan 15, 2019

    @vexx32
    Collaborator

    It's important to remember that while the [ArgumentCompleter()] script block param can refer to other already-entered parameters via a $fakeBoundParameters param in the script block's param() block, the IValidateSetValuesGenerator interface does not provide the same capability as IArgumentCompleter's interface method does.

    It may be possible to copy parts of the code from the [ArgumentCompleter()] constructor that utilises a script block, and the code from IArgumentCompleter in order to permit this much more dynamic and self-referential mode of using ValidateSet, which should make it a far more versatile attribute to work with.

  2. BrucePay commented on Jan 15, 2019

    @BrucePay
    Collaborator

    Josh Olson (@OlsonDev)

    and my coworkers are provided useful IntelliSense from my (arbitrary scriptblocks).

    Are you talking about intellisense in an editor? Running arbitrary code when you are simply editing is problematic from a security standpoint. Consider all the problems that Word macros caused. Or an evil.ps1 script file:

    [CmdletBinding()]
    param (
        [ValidateSet({Remove-Item -Force -Recurse ~})]
        $Repo = "foo"
    )
  3. lzybkr commented on Jan 15, 2019

    @lzybkr
    Contributor

    Bruce Payette (@BrucePay) -

    Running arbitrary code when you are simply editing is problematic from a security standpoint.

    That ship sailed a long time ago - parameter name completion has invoked the dynamicparam block since it was introduced.

  4. BrucePay commented on Jan 16, 2019

    @BrucePay
    Collaborator

    Jason Shirk (@lzybkr) We don't instantiate functions until runtime. Without running the script, how is the dynamic parameter block getting turned into executable code?

  5. lzybkr commented on Jan 16, 2019

    @lzybkr
    Contributor

    It falls out naturally when asking for the parameter metadata - PSScriptCmdlet implements IDynamicParameters.

    If you ask for the parameter metadata, e.g. to invoke the command or for parameter name completion, you must also query the cmdlet for it's dynamic parameters via IDynamicParameters.

    The actual compilation is always on demand, so in this case, it's the implementation of PSScriptCmdlet.GetDynamicParameters that kicks off the compilation.

  6. OlsonDev commented on Jan 19, 2019

    @OlsonDev
    Author

    Bruce Payette (@BrucePay)

    Are you talking about intellisense in an editor? Running arbitrary code when you are simply editing is problematic from a security standpoint. Consider all the problems that Word macros caused. Or an evil.ps1 script file:

    [CmdletBinding()]
    param (
        [ValidateSet({Remove-Item -Force -Recurse ~})]
        $Repo = "foo"
    )

    I more so meant command completion in the PowerShell console window -- in which case, (my coworkers at least) have the source to every command and every command we maintain is code reviewed when changed/added. I don't really view this kind of completion as any more risky than running a command without digging into its source; it could do anything after all.

  7. JustinGrote commented on Mar 18, 2019

    @JustinGrote
    Contributor

    Josh Olson (@OlsonDev) I agree, not any more risky than running a command really, just occurs maybe a little sooner. I suppose the validation code could be put in a constrained runspace but seems like a lot of overhead for little benefit.

    FYI as a workaround that is both Core and WinPS compatible, you can use Register-ArgumentCompleter for the autocomplete part and pass it a scriptblock, and (if you're really paranoid) then have one of the first lines of your code run the same scriptblock, compare the result, and throw an error. The error can have basically the same text as ValidateSet, so you get effectively the same result.

    function Get-TestArgumentValues {
        (get-module).name
    }
    
    Register-ArgumentCompleter -CommandName Test-ArgumentCompleter -ScriptBlock {Get-TestArgumentValues}
    
    function Test-ArgumentCompleter ($argument) {
        #This part is optional but recommended
        $TestArgumentValues = Get-TestArgumentValues
        if ($argument -notin $TestArgumentValues) {throw "Parameter invalid, you must specify one of the following options: $($TestArgumentValues -join ', ')"}
        #End Optional Part
    
        echo $argument
    }
    
    #Now try Test-ArgumentCompleter -Argument [tab]

    You can also dynamically generate an enum on module import and set your parameter type to that, but then you have to get the enum into the "user" scope because of how dumb classes are. The above is "cleaner" in my opinion.

  8. vexx32 commented on Mar 18, 2019

    @vexx32
    Collaborator

    I have some other alternatives for this purpose listed in my blog post here:

    https://vexx32.github.io/2018/11/29/Dynamic-ValidateSet/

    But yes, given that the implementation via class is already a thing, I don't really see how that's all that different to just accepting and using a script block just like ArgumentCompleter already does.

  9. JustinGrote commented on Mar 18, 2019

    @JustinGrote
    Contributor

    Rain Sallow (/u/ta11ow) (@vexx32) I agree, the class already has the functionality in PSCore so the decision has already been made that this is "OK", so going forward the syntax should be able to be simplified to just a scriptblock to make it more intuitive for less advanced powershell users :)

  10. exproject commented on Aug 24, 2019

    @exproject

    I do wish this was implemented as for my current workflow, it would work a wonder. Trying to use IValidateSetValuesGenerator now, but it's just not very intuitive.

  11. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  12. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  13. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  14. microsoft-github-policy-service commented on Nov 23, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassifResolution-No ActivityIssue has had no activity for 6 months or moreWG-Interactive-IntelliSensetab completion

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions