Comparison, Logical, Matching, Replacement, Collection, and Type Operators
Use PowerShell comparison, wildcard, regex, replacement, containment, type, and logical operators while understanding case rules, collection filtering behavior, captures, and short-circuit evaluation.
Learning objectives
- Use equality and ordering operators, including explicit case-sensitive string variants.
- Predict the difference between scalar comparison and collection-filtering comparison behavior.
- Choose wildcard matching for simple patterns and regular expressions for richer matching/capture requirements.
- Use $Matches safely after regex matches and apply -replace for intentional text transformation.
- Use -contains/-in and -is/-isnot/-as for membership and type-related questions.
- Combine decisions with logical operators and short-circuit behavior without creating unreadable conditions.
1. Comparison operators ask questions about values
PowerShell comparison operators return results based on the left and right operands. The core numeric/ordering operators are -eq (equal), -ne (not equal), -lt, -le, -gt, and -ge. Their word-like spelling avoids ambiguity with redirection symbols used by shells.
5 -eq 5
5 -ne 8
3 -lt 10
10 -ge 10True
True
True
TrueType conversion can influence comparisons. PowerShell often converts the right operand toward the type of the left operand. This means operand order can matter when types differ. Boundary validation is safer than relying on clever coercion.
2. String comparisons are case-insensitive by default; c-prefixed variants are explicit
The ordinary string operators are case-insensitive. Prefix the operator name with c for a case-sensitive comparison or i to state case-insensitive intent explicitly.
'Prod' -eq 'prod'
'Prod' -ceq 'prod'
'Prod' -ieq 'prod'True
False
TrueFor identifiers where case carries meaning—some Unix paths, cryptographic text, or case-sensitive external APIs—choose the case-sensitive operator deliberately. For human labels such as environment names, case-insensitive comparison may be the better contract.
3. A collection on the left can turn comparison into filtering
This is one of PowerShell’s most important comparison surprises. When the left operand is a collection, equality and matching operators can return the elements that matched rather than one Boolean.
$states = 'ready', 'failed', 'ready', 'starting'
$states -eq 'ready'
($states -eq 'ready').Countready
ready
2This behavior is useful for concise filtering, but it is why a null test is safer as $null -eq $value rather than $value -eq $null when $value might be a collection. If you need one yes/no answer about a collection, choose a containment operator or evaluate the filtered result explicitly.
4. -like uses wildcard patterns for simple shell-style matching
Wildcard matching is appropriate when your question is simple: “does this filename start with release- and end with .zip?” The common wildcard tokens are * for any sequence of characters and ? for one character.
'release-2026.08.zip' -like 'release-*.zip'
'app-prod-01' -like 'app-*-??'
'README.md' -notlike '*.zip'PowerShell wildcards are not regular expressions. Do not add regex punctuation unless the wildcard language actually uses it. When the matching rule involves character classes, captures, anchors, or complex alternatives, use -match instead.
5. -match and -replace use regular expressions
A regular expression (regex) is a pattern language for text. Start with a narrow mental model: the regex describes which character sequence should be recognized. Anchors such as ^ and $ mean beginning and end of the string; parentheses can capture a meaningful part.
$versionTag = 'release-2.7.1'
if ($versionTag -match '^release-(\d+\.\d+\.\d+)$') {
"Captured version: $($Matches[1])"
}
'api_prod_01' -replace '_', '-'Captured version: 2.7.1
api-prod-01$Matches is an automatic variable populated by a successful scalar -match. Index 0 contains the entire match; numbered indexes contain capture groups. Read it promptly—another match operation can replace its contents. For complicated validation, named capture groups can make the result clearer.
6. -contains and -in answer membership questions
-contains reads “collection contains value.” -in reads “value is in collection.” They express the same membership relationship from opposite directions and return a Boolean.
$allowed = 'dev', 'staging', 'prod'
$environment = 'staging'
$allowed -contains $environment
$environment -in $allowedTrue
TrueUse whichever direction reads naturally. Do not confuse -contains with substring search: 'catalog-api' -contains 'api' does not ask whether one string contains another substring.
7. -is, -isnot, and -as ask about types and conversions
-is checks whether a value has or inherits from a type. -isnot negates that question. -as attempts a conversion and returns $null instead of throwing when conversion is not possible for supported conversions.
$value = 42
$value -is [int]
$value -isnot [string]
$goodVersion = '2.7.1' -as [version]
$badVersion = 'not-a-version' -as [version]
$goodVersion
$null -eq $badVersion-as is convenient when “not convertible” is an expected branch. When invalid input should be an error with context, an explicit cast inside try/catch is often easier to diagnose.
8. Logical operators combine Boolean decisions and short-circuit
-and requires both sides to be true, -or requires at least one, -xor requires exactly one, and -not/! negates a Boolean result. PowerShell evaluates -and and -or from left to right and short-circuits: once the answer is known, the remaining expression is not evaluated.
$environment = 'prod'
$replicas = 4
($environment -eq 'prod') -and ($replicas -ge 3)
$config = $null
($null -ne $config) -and ($config.Enabled -eq $true)The second expression safely returns False without trying to access .Enabled, because the left side of -and is already false. Short-circuit behavior is useful for guard conditions, but keep expressions readable.
9. Build validation as a sequence of understandable questions
Combine the operators around one realistic release candidate rather than writing a single opaque condition.
$artifact = [pscustomobject]@{
FileName = 'release-2.7.1-linux-x64.zip'
Service = 'catalog-api'
Version = '2.7.1'
Environment = 'prod'
SizeMB = 128
}
$allowedEnvironments = 'staging', 'prod'
$allowedServices = 'catalog-api', 'worker'
$isZip = $artifact.FileName -like '*.zip'
$hasReleaseName = $artifact.FileName -match '^release-'
$environmentAllowed = $artifact.Environment -in $allowedEnvironments
$serviceAllowed = $allowedServices -contains $artifact.Service
$version = $artifact.Version -as [version]
$sizeAllowed = $artifact.SizeMB -gt 0 -and $artifact.SizeMB -le 500
$isValid = $isZip -and $hasReleaseName -and $environmentAllowed -and `
$serviceAllowed -and ($null -ne $version) -and $sizeAllowed
$isValidEach intermediate name gives you an observable reason if validation fails. Lesson 05 will turn dense expressions into readable steps systematically.
10. Diagnose scalar-versus-collection mistakes explicitly
$names = 'api', 'worker', 'web'
# Filtering behavior: result is matching element(s), not one Boolean.
$names -eq 'worker'
# Membership behavior: one Boolean.
$names -contains 'worker'
# One Boolean based on filtered count.
($names -eq 'worker').Count -gt 0When reviewing a comparison, first ask: is the left operand a scalar or collection? Then ask: do I want matching elements or a yes/no membership result? This simple diagnostic question prevents a large class of subtle conditions.
11. Lab: validate artifact metadata and extract a semantic version
$artifacts = @(
[pscustomobject]@{ File='release-2.7.1-linux-x64.zip'; Service='catalog-api'; Env='prod'; SizeMB=128 },
[pscustomobject]@{ File='release-2.8.0-rc1-linux-x64.zip'; Service='worker'; Env='staging'; SizeMB=142 },
[pscustomobject]@{ File='notes.txt'; Service='catalog-api'; Env='dev'; SizeMB=1 },
[pscustomobject]@{ File='release-3.0.0-windows-x64.zip'; Service='unknown'; Env='prod'; SizeMB=620 }
)
$allowedEnv = 'staging', 'prod'
$allowedService = 'catalog-api', 'worker'
$results = foreach ($artifact in $artifacts) {
$filePatternOk = $artifact.File -match '^release-(\d+\.\d+\.\d+)(?:-[^-]+)?-.+\.zip$'
$capturedVersion = if ($filePatternOk) { $Matches[1] } else { $null }
$parsedVersion = $capturedVersion -as [version]
[pscustomobject]@{
File = $artifact.File
EnvironmentOK = $artifact.Env -in $allowedEnv
ServiceOK = $allowedService -contains $artifact.Service
NameOK = $filePatternOk
Version = $parsedVersion
SizeOK = ($artifact.SizeMB -gt 0) -and ($artifact.SizeMB -le 500)
}
}
$results | Format-Table -AutoSize
$valid = $results | Where-Object {
$_.EnvironmentOK -and $_.ServiceOK -and $_.NameOK -and `
($null -ne $_.Version) -and $_.SizeOK
}
$validVerification checklist
12. Knowledge check
Question 1. What does 'Prod' -eq 'prod' return by default?
True. PowerShell string comparisons are case-insensitive by default.Question 2. What is the major difference between $items -eq 'x' and $items -contains 'x'?
-eq can return matching elements; -contains returns one Boolean membership result.Question 3. When should you prefer -like over -match?
-like for simple wildcard patterns. Use -match when you need regular-expression features such as anchors, captures, or richer pattern rules.Question 4. What happens to $Matches after a successful scalar -match?
Question 5. What does short-circuiting mean for -and?
-and expression is false and does not evaluate the right side.13. Summary
PowerShell’s comparison operators are expressive because they work with types and collections, but that flexibility makes operand shape important. Use explicit case-sensitive variants when required, wildcards for simple patterns, regex for richer matching/captures, containment operators for membership, type operators for type questions/conversion attempts, and logical operators to combine decisions. When a condition becomes hard to read, name the intermediate questions instead of relying on operator cleverness.
14. Further reading
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this address.