0

I have the following code, where I try to create a custom Cmdlet for PowerShell using C#.

What I want to do with my custom cmdlet is that, user should call it with two parameters, from which first one should be -Text or -File or -Dir, and the next one should be a value, a string which specifies the value for text, or file, or directory.

The point is that if I try to call my cmdlet with a parameter -Test for example, which is of course a wrong parameter, I don't get the value of the default statement, which says "Bad parameter name".

I guess my code just don't get till the default part of the switch.

By the way, SHA256Text, SHA256File, and SHA256Directory, are just custom helper methods that I have written, so don't worry about them.

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Management.Automation;

namespace PSSL
{
    [Cmdlet(VerbsCommon.Get, "SHA256")]
    public class GetSHA256 : PSCmdlet
    {
        #region Members

        private bool text;
        private bool file;
        private bool directory;
        private string argument;

        #endregion

        #region Parameters

        [Parameter(Mandatory = true, Position = 0, ParameterSetName = "Text")]
        public SwitchParameter Text
        {
            get { return text; }
            set { text = value; }
        }

        [Parameter(Mandatory = true, Position = 0, ParameterSetName = "File")]
        public SwitchParameter File
        {
            get { return file; }
            set { file = value; }
        }

        [Parameter(Mandatory = true, Position = 0, ParameterSetName = "Directory")]
        public SwitchParameter Dir
        {
            get { return directory; }
            set { directory = value; }
        }

        [Parameter(Mandatory = true, Position = 1)]
        [ValidateNotNullOrEmpty]
        public string Argument
        {
            get { return argument; }
            set { argument = value; }
        }

        #endregion

        #region Override Methods

        protected override void ProcessRecord()
        {
            switch(ParameterSetName)
            {
                case "Text":
                    SHA256Text(argument);
                    break;

                case "File":
                    SHA256File(argument);
                    break;

                case "Directory":
                    SHA256Directory(argument);
                    break;

                default:
                    throw new ArgumentException("Error: Bad parameter name.");
            }
        }

        #endregion
    }
}
  • 3
    Does it reach ProcessRecord at all? If it does, are you sure there isn't any of the cases from the switch get executed? Because you make it sound the C# compiler is broken. And I very much doubt that is the problem. PS: How about making the use of your CmdLet easier by defining a default parameterset? [Cmdlet(VerbsCommon.Get, "SHA256", DefaultParameterSetName = "Text")] – Lars Truijens May 05 '13 at 11:43

2 Answers2

2

Lars is correct. The parameter binder is a separate procedure external to your cmdlet. If the syntax is not correct, the cmdlet is not even executed.

x0n
  • 51,312
  • 7
  • 89
  • 111
  • The point is that, if I call my function like: Get-SHA256 -Text "Some text here.", it works just fine, also using -File or -Dir options yield good results. If I don't write the first or second argument, or write something other, like -Test let's say, it doesn't work of course. But I cannot seem to find the error message: Bad parameter name displayed somewhere. –  May 06 '13 at 17:01
  • 1
    @erkant - you won't see that error message. You're not understanding at all what we're saying. Your cmdlet is NOT the thing that verifies parameters. Powershell verifies them before running your cmdlet. It reads the metadata from the command. The command does not ever run if parameters are not valid, hence you will NEVER see your message. – x0n May 06 '13 at 21:12
2

Since PowerShell does not have enough information to 'bind' to the parameters, ProcessRecord is not called at all, and instead gives an error. So you never see your switch getting executed.

Parameter set cannot be resolved using the specified named parameters. + CategoryInfo : InvalidArgument: (:) [], ParameterBindingException + FullyQualifiedErrorId : AmbiguousParameterSet,

You should not even want to. Let PowerShell handle the parameters. You can fix your CmdLet by doing the following:

  1. Remove the Position = 0 for the SwitchParameters. It's not logical to have positional SwitchParameters. PowerShell can detect SwitchParameters with ease in any position
  2. Do not make the SwitchParameters mandatory. It is of no use. The switch is either there or not, true or false. Forcing it to be there does not make sense. It's like forcing it to be true.
  3. Give your CmdLet a DefaultParameterSetName. Logical would be to chose one of the defined parameter sets, like 'Text'
  4. Make your Argument parameter Position = 0. Since the SwitchParameters don't need a position this is the first.

Now you can call it like this:

Get-SHA256 'SomeText'
Get-SHA256 'SomeText' -Text
Get-SHA256 -Text 'SomeText'
Get-SHA256 'C:\Some.File' -File
Get-SHA256 -File 'C:\Some.File'
etc

Also consider checking the SwitchParameters values instead of switching on the ParameterSetName. SwithParameters can be called like -File:$false. Fall back to your default.

Lars Truijens
  • 42,837
  • 6
  • 126
  • 143