Why is this condition being met when verifying parameters using the -notMatch condition?

Viewed 78

I am validating parameters passed into a release pipeline with Powershell. The parameter I am passing as a pipeline variable is val1. Here is my code below:

if ("$(Value)" -notMatch "val1" -or "$(Value)" -notMatch "val2"){
  Write-Host "$(Value) must be val1 || val2"
  Write-Host "Value of param: "$(Value)""
  exit 1
}

When I print my value is states val1. Why is this condition being met? I thought perhaps it was because its case sensitive however even when I modify the condition to catch the exact case, it's still being met.

3 Answers

If your variable should have only val1 or val2, you have to use -and instead -or.

if ("$(Value)" -notMatch "val1" -and "$(Value)" -notMatch "val2"){
  Write-Host "$(Value) must be val1 || val2"
  Write-Host "Value of param: "$(Value)""
  exit 1
}

Change it to

if ("$(Value)" -notMatch "val1" -and "$(Value)" -notMatch "val2"){
  Write-Host "$(Value) must be val1 || val2"
  Write-Host "Value of param: "$(Value)""
  exit 1
}

Note: $(Value) in the question as well as in the code below is an Azure pipeline macro, not a PowerShell variable reference such as $Value. Since such a macro is expanded to its value before PowerShell sees it, enclosing it in "..." - again, as in the question and in the code below - ensures that no syntax error occurs if the value happens to contain spaces or other PowerShell metacharacters.

The Shamrai Aleksander's helpful answer explains the logic error, but there may be an additional problem:

  • -match (and its -notmatch variant), the regular-expression matching operator, matches substrings by default, so that "$(Value)" expanding to aval1, for instance, would mistakenly pass the test as well.

  • for literal, whole-value comparisons against a collection, you can use the -in operator (note that -contains serves the same purpose only with the operands reversed) and its variants, notably -notin in this case; use -cnotin for case-sensitive comparisons.

# Note: `$(Value)` is an *Azure pipeline macro (variable)*, which is expanded
#       *before* PowerShell sees the code.
#       In pure PowerShell code, the equivalent would be just `$Value`
if ("$(Value)" -notin 'val1', 'val2') {
  Write-Error '$(Value) must be val1 || val2'
  exit 1
}

I thought perhaps it was because its case-sensitive however

Note that all PowerShell operators are case-insensitive by default (when they operate on text); PowerShell is case-insensitive by default in most respects.

Case-sensitive operation requires use of the c prefixed variants, such as -cmatch.

Optionally, to signal the intent more clearly, you can signal case-insensitive operation by using the i-prefixed variants, such as -imatch (all i-prefixed variants behave like their non-prefixed base forms).

Related