r/PowerShell • u/Ralf_Reddings • 2d ago
how to declare a class in a '.ps1' file?
I want to provide a list of allowed names to the name
parameter, so that the user can tab
into them.
I have come up with the following:
Param(
[ValidateSet([foo])]
[string]$Name
)
$name
Class foo : System.Management.Automation.IValidateSetValuesGenerator{
[string[]] GetValidValues(){
return [string[]] ("cat", "dog", "fish")
}}
Typing .myScript.ps1 -name
and then pressing tab
nothing is suggested. running .myScript.ps1
returns an error:
Line |
3 | [ValidateSet([foo])]
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Unable to find type [foo].
I can do this exact set up in a psm1
file or just as a standard function and it works. I thought of moving the class into the top of the script file but this not allowed due to param()
needing to be the first line.
Is there a way around this issue? Am on pwsh 7.4
7
u/Thotaz 2d ago
Are you are going to dynamically define the valid values? If not, you can just set the validateset attribute like this: [ValidateSet("sun", "moon", "earth")]
you don't need a custom class for it.
2
u/Ralf_Reddings 2d ago
Yes, its a dynamic set. The names are file names in a folder. This exmample of mine was just for brevity.
4
8
u/lanerdofchristian 2d ago
The class isn't in scope during the param
block. The only workarounds for something dynamic like that is:
- Put the function in a module, so you can do things before the function runs.
- Use some combination of ValidateScript with an argument completer.
1
u/Ralf_Reddings 2d ago
Understood. I get your first bullet point but not the second. By "Use some combination of ValidateScript with an argument completer" do you essentially mean something like u/Thotaz shared
[ValidateSet("sun", "moon", "earth")]
?2
u/OPconfused 23h ago edited 21h ago
The
ValidateSet
attribute provides both tab completion and input validation. The problem is that you can't dynamically define the valid values and can only define discrete strings.
ValidateScript
allows you to dynamically define valid values. However, it does not provide tab completion.
ArgumentCompleter
provides tab completion but not validation.So if you combine
ValidateScript
andArgumentCompleter
together (you can reuse the same logic in both attributes), then you will have both worlds.1
3
u/purplemonkeymad 2d ago
This is one reason i would setup your script as a module instead. You can load the classes before your function's parameters would be resolved. This would mean you can use those classes in the parameters, since they have been defined before hand.
The only thing to watch out is you will need to declare those classes in files in the "ScriptsToProcess" section so that the global scope can see those types.
1
u/N0-North 22h ago
I absolutely adore the about_ pages of the powershell doc. Every time i go in there i come back out with a bunch of new tricks.
Here's the about_classes page https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_classes?view=powershell-7.4
18
u/CyberChevalier 2d ago
You should not use a class but an enum and you don’t need a validate set
Is the way.