Relational operators (also known as comparison operators) compare two or more values, test strings against pattern rules, and filter arrays. Unlike languages that use symbolic notation (such as ==, !=, <, >), PowerShell uses hyphenated text tokens (-eq, -ne, -gt, -lt). When applied to scalar values, these operators return a boolean ($true or $false). When applied to collections, they act as high-speed data filters, returning all matching elements.
Equality and Comparison Operators
PowerShell provides six primary numeric and structural comparison operators:
| Operator | Meaning | Example Expression | Scalar Result |
|---|---|---|---|
-eq |
Equal to | 10 -eq 10 |
$true |
-ne |
Not equal to | 10 -ne 20 |
$true |
-gt |
Greater than | 15 -gt 10 |
$true |
-ge |
Greater than or equal to | 10 -ge 10 |
$true |
-lt |
Less than | 5 -lt 10 |
$true |
-le |
Less than or equal to | 10 -le 10 |
$true |
$ServicePort = 8080
$MaxAllowedPort = 1024
[PSCustomObject]@{
IsPrivilegedPort = ($ServicePort -le $MaxAllowedPort)
IsStandardHttp = ($ServicePort -eq 80)
IsCustomPort = ($ServicePort -gt $MaxAllowedPort)
}pwsh ./scalar-comparison.ps1IsPrivilegedPort IsStandardHttp IsCustomPort
---------------- -------------- ------------
False False TrueCollection Filtering Behavior
When the left-hand operand of a comparison operator is an array or collection, PowerShell changes its behavior. Instead of returning a single boolean $true or $false, it returns an array containing only the elements that satisfy the condition:
$Numbers = 10, 20, 30, 40, 50
$Numbers -gt 25
$Names = "web01", "sql01", "app01", "sql02"
$Names -like "sql*"30
40
50
sql01
sql02Case Sensitivity: Prefix Modifiers (c vs. i)
By default, all relational operators in PowerShell are case-insensitive. For example, "powershell" -eq "POWERSHELL" evaluates to $true.
To explicitly declare or override case behavior, prefix the operator with either i (case-insensitive, default) or c (case-sensitive):
| Case-Insensitive (Default) | Case-Sensitive | Example Expression | Result |
|---|---|---|---|
-eq or -ieq |
-ceq |
"Admin" -ceq "admin" |
$false |
-ne or -ine |
-cne |
"Admin" -cne "admin" |
$true |
-like or -ilike |
-clike |
"Test" -clike "t*" |
$false |
-match or -imatch |
-cmatch |
"Prod" -cmatch "[A-Z]{4}" |
$false |
"System Administrator" -match "admin"
"System Administrator" -cmatch "admin"True
FalseWildcard Matching: -like and -notlike
The -like and -notlike operators evaluate string expressions using standard PowerShell wildcard patterns, similar to file system searches.
Supported Wildcard Characters
| Wildcard | Description | Example Pattern | Matches |
|---|---|---|---|
* |
Matches zero or more arbitrary characters | "web-prod-01" -like "web*" |
$true |
? |
Matches exactly one single character | "disk1" -like "disk?" |
$true |
[abc] |
Matches any single character within the enclosed set | "logB" -like "log[AB]" |
$true |
[a-z] |
Matches any single character within the specified ASCII range | "core3" -like "core[0-9]" |
$true |
$LogFileA = "system-audit-2026.log"
$LogFileB = "temp-cache.tmp"
[PSCustomObject]@{
IsAuditFile = ($LogFileA -like "system-*-2026.???")
IsLogFormat = ($LogFileA -like "*.log")
IsExcluded = ($LogFileB -notlike "*.log")
}pwsh ./wildcard-matching.ps1IsAuditFile IsLogFormat IsExcluded
----------- ----------- ----------
True True Truewhere:
"*.csv"matches any string ending in.csv, regardless of what precedes it."report_????.csv"matches exactly four characters betweenreport_and.csv.-notlikereturns$truewhen the pattern does not match.
Regular Expression Matching: -match and -notmatch
The -match and -notmatch operators evaluate string data against .NET regular expressions (regex). Unlike -like (which requires wildcards to match the entire string from start to finish), -match succeeds if the regular expression pattern matches any substring within the target text, unless explicitly anchored with ^ (start) or $ (end).
"user@example.com" -match "^\w+@\w+\.\w+$"
"12345" -match "^\d+$"
"abc123" -notmatch "^\d+$"True
True
Truewhere:
^\w+@\w+\.\w+$validates a simple email-like pattern using regex anchors (^,$) and character classes (\w,\d).-notmatchreturns$truewhen the pattern does not match the string.
The $Matches Automatic Variable
When -match evaluates to $true on a scalar string, PowerShell automatically populates the $Matches automatic variable with a hashtable containing the full matched text (at key 0) and any extracted capture groups:
$LogEntry = "2026-10-24 14:32:00 [CRITICAL] Database node SQL-PROD-02 connection timeout."
$Pattern = '\[(?<Severity>[A-Z]+)\] Database node (?<NodeName>[A-Z0-9-]+)'
if ($LogEntry -match $Pattern) {
[PSCustomObject]@{
SeverityLevel = $Matches['Severity']
ImpactedNode = $Matches['NodeName']
FullMatchText = $Matches[0]
}
}where:
\[escapes literal brackets.(?<Severity>[A-Z]+)creates a named capture group matching consecutive uppercase letters.(?<NodeName>[A-Z0-9-]+)creates a named capture group matching alphanumeric hostnames.$Matches['Severity']retrieves the captured data from the automatic hashtable.
pwsh ./regex-capture.ps1SeverityLevel ImpactedNode FullMatchText
------------- ------------ -------------
CRITICAL SQL-PROD-02 [CRITICAL] Database node SQL-PROD-02Positional Capture Groups
You can also use positional capture groups with parentheses:
"Order-2026-0091" -match "Order-(\d+)-(\d+)"
$matches[0]
$matches[1]
$matches[2]True
Order-2026-0091
2026
0091where:
$matches[0]contains the entire matched string.$matches[1]and$matches[2]contain the values captured by each parenthesized group(\d+)in order.
Choosing the Right Operator
| Scenario | Recommended Operator |
|---|---|
| Comparing numbers or exact strings | -eq, -ne, -gt, -lt, -ge, -le |
| Simple filename or basic pattern checks | -like, -notlike |
| Complex pattern validation or extraction | -match, -notmatch |
Practical Example: Automated System Process and Security Audit
The following script inspects active processes, using numeric comparison operators to identify high-memory consumers, wildcard matching to locate system services, and regular expressions to parse command-line metadata:
param (
[double]$MemoryThresholdMB = 200.0
)
$HighMemoryProcesses = Get-Process | Where-Object {
($_.WorkingSet64 / 1MB) -ge $MemoryThresholdMB
}
$AuditReport = foreach ($proc in $HighMemoryProcesses) {
$procName = $proc.ProcessName
$memoryMB = [math]::Round($proc.WorkingSet64 / 1MB, 2)
$isHostWorker = ($procName -like "*host*" -or $procName -like "*worker*")
$workloadCategory = switch -Regex ($procName) {
"^(chrome|msedge|firefox)$" { "Web Browser" }
"^(code|devenv|rider)$" { "Development IDE" }
"^sql|mongod|postgres" { "Database Engine" }
Default { "System/Background Task" }
}
[PSCustomObject]@{
PID = $proc.Id
ProcessName = $procName
MemoryUsageMB = $memoryMB
ExceedsCritical = ($memoryMB -gt 1000.0)
IsHostWorker = $isHostWorker
Category = $workloadCategory
}
}
$AuditReport | Sort-Object -Property MemoryUsageMB -Descending | Select-Object -First 2where:
($_.WorkingSet64 / 1MB) -ge $MemoryThresholdMBuses-geto filter numeric memory values.($procName -like "*host*")uses wildcards to identify background hosts.switch -Regex ($procName)matches process names against regular expression patterns (^,$,|).($memoryMB -gt 1000.0)uses-gtto flag memory usage exceeding 1 GB.
Execute the script from the console:
pwsh ./audit-process-workload.ps1 -MemoryThresholdMB 150.0PID : 1300
ProcessName : Memory Compression
MemoryUsageMB : 207.73
ExceedsCritical : False
IsHostWorker : False
Category : System/Background Task
PID : 6184
ProcessName : explorer
MemoryUsageMB : 201.44
ExceedsCritical : False
IsHostWorker : False
Category : System/Background Task