How do you enumerate the available hashing algorithms when HashCmdletBase.Algorithm is a string?
PowerShell gets the information from ValidateSet attribute:
https://github.com/PowerShell/PowerShell/blob/fc8ca61b3dd2a561d7fe8fbc38fd779278ad7984/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetHash.cs#L234-L245
Yeah, but how do you do that in PowerShell?
With an enum you would just do, for example, [System.ConsoleColor].GetEnumNames().
One way is:
(Get-Command Get-FileHash).Parameters['Algorithm'].Attributes.Where{$_ -is [ValidateSet]}.ValidValues
But in general usage you can simply do Get-FileHash -Algorithm <tab> and tab through the available values.
A quick-and-dirty approach is to provoke an error by passing a deliberately invalid value. The resulting error message then contains a list of all valid values:
PS> Get-FileHash -Algorithm TotallyBogus
Get-FileHash: Cannot validate argument on parameter 'Algorithm'.
The argument "TotallyBogus" does not belong to the set "SHA1,SHA256,SHA384,SHA512,MD5" specified
by the ValidateSet attribute. Supply an argument that is in the set and then try the command again.
Even easier: Get-FileHash -? enumerates the valid values too.
Is there any reason why this isn't an enum?
Is there any reason why this isn't an enum?
Backward compatibility. The cmdlet was initially implemented on script, later re-implemented on C#. Changing this would be a breaking change.
How is that a breaking change, exactly?
Whether the parameter is an enum type or not, users would still generally use the argument in the same way, and enums cast from strings in PowerShell without issue.
What exactly would that break?
How is that a breaking change, exactly?
If you were previously relying on conversion to string for that parameter that would break since the binder won't go something > string > enum. That's solved pretty easily with argument transformation, but it's more work. Really there aren't many reasons to enumerate the values outside of help and tab completion so usually it's not worth the trouble.
Also now it would be a breaking change as HashCmdletBase is publicly inheritable.
Really there aren't many reasons to enumerate the values outside of help and tab completion so usually it's not worth the trouble.
.NET is all about types! When you start passing around strings instead of proper types you break fundamental design goals.
There are plenty of reasons why you would want to enumerate, in this example, the different hashing algorithms,for example if you want to display what's available in some kind of UI or a user to choose from.
String should only be used for displaying text which is intended to be read by a human, everything else should have a proper type for its purpose.
.NET is all about types! When you start passing around strings instead of proper types you break fundamental design goals.
Formatted string data for sure I agree there. ValidateSet values are basically PowerShell's zero effort enum.
There are plenty of reasons why you would want to enumerate, in this example, the different hashing algorithms,for example if you want to display what's available in some kind of UI or a user to choose from.
Yeah that's pretty niche. Also if you don't already know the enum type, it's about the same amount of work to enumerate.
String should only be used for displaying text which is intended to be read by a human, everything else should have a proper type for its purpose.
If PowerShell was strictly typed I'd be inclined to agree, but that doesn't apply as much. ValidateSet and PSCustomObject are pretty heavily baked in.
It's a good rule of thumb to use an enum for new API's though definitely.
This issue has been marked as answered and has not had any activity for 1 day. It has been closed for housekeeping purposes.
Most helpful comment
One way is:
But in general usage you can simply do
Get-FileHash -Algorithm <tab>and tab through the available values.