4

What's the best way to do PowerShell cmdlet validation on dependent parameters? For example, in the sample cmdlet below I need to run validation that Low is greater than High but that doesn't seem to be possible with validation attributes.

[Cmdlet(VerbsCommon.Get, "FakeData")]
public class GetFakeData : PSCmdlet
{
    [Parameter(Mandatory = true)]
    [ValidateNotNullOrEmpty]
    public int Low { get; set; }

    [Parameter(Mandatory = true)]
    [ValidateNotNullOrEmpty]
    public int High { get; set; }

    protected override void BeginProcessing()
    {
        if (Low >= High)
        {
            // Is there a better exception to throw here?
            throw new CmdletInvocationException("Low must be less than High");
        }

        base.BeginProcessing();
    }

    protected override void OnProcessRecord()
    {
       // Do stuff...
    }
}

Is there is a better way to do this? The main thing I don't like about the solution above is that I can't throw a ParameterBindingException like the validation attributes would do since it's an internal class. I could throw ArgumentException or PSArgumentException but those are really for Methods not cmdlets.

1 Answer 1

2

You need something like in the cmdlet get-random. Because you can't use [validatescript()] attribute in a cmdlet 'cause it's valid only for powershell function/script at run-time you need to steal the idea from microsoft.powershell.utility\get-random:

The value check is done in the BeginProcessing() and use a customized error ThrowMinGreaterThanOrEqualMax

protected override void BeginProcessing()
    {
      using (GetRandomCommand.tracer.TraceMethod())
      {
        if (this.SetSeed.HasValue)
          this.Generator = new Random(this.SetSeed.Value);
        if (this.EffectiveParameterSet == GetRandomCommand.MyParameterSet.RandomNumber)
        {
          if (this.IsInt(this.Maximum) && this.IsInt(this.Minimum))
          {
            int minValue = this.ConvertToInt(this.Minimum, 0);
            int maxValue = this.ConvertToInt(this.Maximum, int.MaxValue);
            if (minValue >= maxValue)
              this.ThrowMinGreaterThanOrEqualMax((object) minValue, (object) maxValue);
            this.WriteObject((object) this.Generator.Next(minValue, maxValue));
          }
          else
          {
            double min = this.ConvertToDouble(this.Minimum, 0.0);
            double max = this.ConvertToDouble(this.Maximum, double.MaxValue);
            if (min >= max)
              this.ThrowMinGreaterThanOrEqualMax((object) min, (object) max);
            this.WriteObject((object) this.GetRandomDouble(min, max));
          }
        }
        else
        {
          if (this.EffectiveParameterSet != GetRandomCommand.MyParameterSet.RandomListItem)
            return;
          this.chosenListItems = new List<object>();
          this.numberOfProcessedListItems = 0;
          if (this.Count != 0)
            return;
          this.Count = 1;
        }
      }
    }

...

private void ThrowMinGreaterThanOrEqualMax(object min, object max)
    {
      if (min == null)
        throw GetRandomCommand.tracer.NewArgumentNullException("min");
      if (max == null)
        throw GetRandomCommand.tracer.NewArgumentNullException("max");
      string errorId = "MinGreaterThanOrEqualMax";
      this.ThrowTerminatingError(new ErrorRecord((Exception) new ArgumentException(this.GetErrorDetails(errorId, min, max).Message), errorId, ErrorCategory.InvalidArgument, (object) null));
    }

You can use a decompiler ( dotPeak ) to see the rest of the code to learn more on custom error for cmdlet

Sign up to request clarification or add additional context in comments.

1 Comment

That's exactly what I was looking for thanks. I found this MSDN doc for how to create ErrorRecord appropriately: msdn.microsoft.com/en-us/library/ms714465(v=vs.85).aspx, and the remarks section of the ThrowTerminatingError here on MSDN reinforced the usage displayed in your answer: msdn.microsoft.com/en-us/library/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.