Guiri
Guiri

Reputation: 79

elseif statement containing multiple expressions separated by -or failing

I have created a PowerShell script which is basically a simple calculator. The script needs to be passed 3 parameters, the first one being a number, the second one being an arithmetic operator (+ - * /) and the third one being another number, after which the script returns the calculated value.

Initially, the script worked being like this:

param (
  [double]$num1,
  [string]$op,
  [double]$num2
)

switch ($op) {
  "+" {write-host $($num1+$num2)}
  "-" {write-host $($num1-$num2)}
  "*" {write-host $($num1*$num2)}
  "/" {write-host $($num1/$num2)}
}

However, I want to make the script a bit more complex by throwing a different error message for each of these situations:

  1. When no parameters are passed, the message would be "You haven't specified any parameters".

  2. When the second parameter isn't either "+", "-", "*" or "/", the message would be "You haven't specified a valid operator (+ - * /) as the second parameter".

  3. When the previous 2 situations don't occur but no third parameter (the 2nd number) is passed, the message would be "You haven't specified the second number".

So, with this in mind, I made some changes to the script ending up like this:

param (
  [double]$num1,
  [string]$op,
  [double]$num2
)

if ($num1 -eq "") {
  write-host "You haven't specified any parameters"
} elseif (($op -ne "+") -or ($op -ne "-") -or ($op -ne "*") -or ($op -ne "/")) {
  write-host "You haven't specified a valid operator (+ - * /) as the second parameter"
} elseif ($num2 -eq "") {
  write-host "You haven't specified the second number"
} else {
  switch ($op) {
    "+" {write-host $($num1+$num2)}
    "-" {write-host $($num1-$num2)}
    "*" {write-host $($num1*$num2)}
    "/" {write-host $($num1/$num2)}
  }
}

So now, if I don't pass any parameters to the script, I get the "You haven't specified any parameters" message.

If I only pass the first parameter, I get the "You haven't specified a valid operator (+ - * /) as the second parameter", which is good.

But if I pass the first parameter and, as the second parameter I pass either "+", "-", "*" or "/", I still get the "You haven't specified a valid operator (+ - * /) as the second parameter" message so there's something wrong in the first elseif statement, although it seems to be syntactically-correct.

Upvotes: 2

Views: 308

Answers (2)

mjolinor
mjolinor

Reputation: 68273

Think about your condition statement:

elseif (($op -ne "+") -or ($op -ne "-") -or ($op -ne "*") -or ($op -ne "/"))

The -or means if any of them are true, then the whole test is true. What you want is for the whole test to be true only if all of them are true.

What can you do to fix that?

Upvotes: 1

briantist
briantist

Reputation: 47792

Use Advanced Function Parameter Options

The solution mjolinor is suggesting (in his comment) would look something like this:

[CmdletBinding()]
param(
    [Parameter(
        Mandatory=$true
    )]
    [double]
    $num1,

    [Parameter(
        Mandatory=$true
    )]
    [ValidateSet('+', '-', '*', '/')]
    [string]
    $op,

    [Parameter(
        Mandatory=$true
    )]
    [double]
    $num2
)

    switch ($op) {
           "+" {write-host $($num1+$num2)}
           "-" {write-host $($num1-$num2)}
           "*" {write-host $($num1*$num2)}
           "/" {write-host $($num1/$num2)}
    }

This has the added benefit of letting you tab complete the operator.

Your Solution

The reason yours isn't working is because you're using -or when you should be using -and:

elseif (($op -ne "+") -and ($op -ne "-") -and ($op -ne "*") -and ($op -ne "/"))

It can get confusing because of the fact that you're checking for the negative condition (i.e. if (an_invalid_value)) where the conditions inside are negated (-ne).

Consider what happens in your version if you choose minus -: You evaluate $op -ne '+' and this is true, so condition satisfied, nothing else is tested, you go right to telling the user they did the wrong thing. With -and, all of the -ne conditions would need to be satisfied.

Here's an even simpler way of doing it your way:

elseif ( ('+','-','*','/') -notcontains $op)

Basically you say "if this array of operators does not contain $op, then display the error." It's much easier to follow.

But what's really much easier, and safer, and maintainable, is to use the built-in parameter validation options. Learn them; they're great!

Upvotes: 4

Related Questions