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 10
True
True
True
True
Type 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
True
For 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').Count
ready
ready
2
This 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 $allowed
True
True
Use 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
$isValid
Each 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 0
When 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
}
$valid
Verification 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.