Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
181 views
in Technique[技术] by (71.8m points)

regex - PowerShell array containing integer '0' does not match "^(0|3010)$"

I am trying to process return codes for multiple installers using a -match statement. I would expect the following code to return 'Installer(s) ran successfully' twice - but the -match statement does not work with an integer array containing the value 0...

$InstallerExitCodes = @()

$InstallerExitCodes += 0 # Pretend this is (Start-Process -PassThru -Wait installer.exe).ExitCode which returns 0 (success)

If ($InstallerExitCodes -match "^(0|3010)$") {
    Write-Output "Installer(s) ran successfully" # This does not run
}

$InstallerExitCodes += 3010 # Pretend this is (Start-Process -PassThru -Wait installer.exe).ExitCode which returns 3010 (success with reboot required)

If ($InstallerExitCodes -match "^(0|3010)$") {
    Write-Output "Installer(s) ran successfully" # This does
}
question from:https://stackoverflow.com/questions/65920559/powershell-array-containing-integer-0-does-not-match-03010

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It certainly matches 0 - the problem is not the regex comparison, it's the if statement.

PowerShell's scalar comparison operators have 2 modes of operation:

  • Scalar mode: when the left-hand side operand is not enumerable, like 1 -eq 1, PowerShell returns the boolean result of the comparison - that is, the expression evaluates to either $true or $false.
  • Filter mode: when the left-hand side operator is enumerable, the comparison operator acts like a filter: 1,2,3 -gt 1 does not return $true or $false, it returns an array consisting of the items 2 and 3, since they satisfied the constraint -gt 1.

Since $InstallerExitCodes is explicitly declared as an array, -match works in filter mode, and the result of the expression is no longer $true or $false (simplified):

PS C:> @(0) -match '^0$'
0

The if() context makes PowerShell convert the expression result to [bool], and since 0 is a falsy value, the if condition fails.

Either change the if condition to check for the count of the resulting filter mode expression:

if(@($InstallerExitCodes -match "^(0|3010)$").Count -ge 1){
  # success!
}

or use a containment operator to test:

if($InstallerExitCodes -contains 0 -or $InstallerExitCodes -contains 3010){
  # success!
}

or, you know, test the exit codes individually, instead of as a collection :-)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...