PowerShell String Comparison: -eq, -like, -match Explained

Picking the wrong string comparison operator in PowerShell silently returns wrong results — -contains checks array membership, not substrings; -match is case-insensitive by default; and -eq works differently on arrays than scalars. PowerShell string comparison with -eq, -like, and -match each serves a distinct purpose, and knowing which to use prevents subtle bugs that are painful to diagnose after the fact. This post defines each operator clearly with working examples.
Exact Match with -eq and -ne
-eq performs an exact string comparison and returns $true if the strings are identical. It is case-insensitive by default. -ne is the inverse.
# Basic equality
"PowerShell" -eq "powershell" # True (case-insensitive)
"PowerShell" -eq "Python" # False
# Inequality
"Production" -ne "Development" # True
# Use in Where-Object filtering
Get-Process | Where-Object { $_.Name -eq "notepad" }
# PS3+ simplified syntax
Get-Process | Where-Object Name -eq "notepad"
When -eq is applied to an array on the left side, it returns the matching elements rather than a Boolean — a useful filter pattern:
$colors = @("Red", "Green", "Blue", "red")
$colors -eq "Red" # Returns: Red, red (all case-insensitive matches)
Case-Sensitive Variants -ceq, -cne
Prefix any comparison operator with c to make it case-sensitive. Prefix with i to explicitly force case-insensitivity (though this is the default).
# Case-sensitive comparison
"PowerShell" -ceq "PowerShell" # True
"PowerShell" -ceq "powershell" # False
# Case-insensitive (explicit — same as default -eq)
"PowerShell" -ieq "powershell" # True
# Case-sensitive -like, -match, -contains also work with c prefix
"hello" -clike "Hello" # False
"hello" -clike "hello" # True
Wildcard Match with -like
-like matches using shell-style wildcards: * for zero or more characters, ? for exactly one character. It is case-insensitive by default. Use -clike for case-sensitive wildcard matching.
# Wildcard patterns
"PowerShell" -like "Power*" # True
"PowerShell" -like "*Shell" # True
"PowerShell" -like "Power?hell" # True (? matches 'S')
"PowerShell" -like "*script*" # False
# Filter files by pattern
Get-ChildItem "C:\Logs" | Where-Object { $_.Name -like "*.log" }
# Service names matching a pattern
Get-Service | Where-Object Name -like "sql*"
Regex Match with -match
-match compares a string against a regular expression pattern. It is case-insensitive and populates $Matches with capture group results. Use for complex patterns that wildcards cannot express.
# Simple match
"[email protected]" -match "@" # True
"192.168.1.100" -match "^\d{1,3}\." # True
# Extract with capture groups
"Error at line 42" -match "line (\d+)"
$Matches[1] # Returns: 42
# Case-sensitive regex
"PowerShell" -cmatch "powershell" # False
"PowerShell" -cmatch "PowerShell" # True
Contains vs -contains vs .Contains()
This is the most common source of confusion in PowerShell string comparisons. Three things with “contains” in their name do three completely different things:
# -contains checks if an ARRAY contains an element (NOT substring)
$array = @("cat", "dog", "fish")
$array -contains "dog" # True — "dog" is in the array
"cat" -contains "ca" # WRONG USE — returns False, not what you expect
# .Contains() is a string METHOD — checks substring
"PowerShell".Contains("Shell") # True
"PowerShell".Contains("script") # False (case-sensitive!)
# To check substring (case-insensitive), use -like or -match
"PowerShell" -like "*shell*" # True
"PowerShell" -match "shell" # True
Performance Comparison
For large collections where performance matters, the choice of operator affects throughput significantly:
-eq— fastest for exact scalar matches-like— faster than-matchfor simple wildcard patterns-match— most flexible but regex has compilation overhead; for repeated use, compile the regex once:$regex = [regex]"pattern"
# Pre-compile regex for repeated use in large loops
$regex = [regex]::new("^\d{4}-\d{2}-\d{2}$", [System.Text.RegularExpressions.RegexOptions]::Compiled)
$lines = Get-Content "C:\Logs\big-file.log"
$matches = $lines | Where-Object { $regex.IsMatch($_) }
Common Errors and Fixes
- -contains tests array membership not substring: This is the single most common string comparison mistake in PowerShell.
"hello world" -contains "hello"returns$falsebecause-containschecks if the array on the left contains the element on the right — and a scalar string treated as a single-element array does not contain the substring"hello". Use.Contains(),-like "*hello*", or-match "hello"for substring checks. - -match is case-insensitive by default:
"ERROR" -match "error"returns$true. If you’re writing validation logic that depends on case sensitivity — for example, checking a specific log level format — use-cmatchto ensure the case must match exactly.
Related Cmdlets / See Also
Wrapping Up
The quick reference: -eq for exact match, -like for wildcards, -match for regex, and .Contains() for substring checks (not -contains). As a next step, search your existing scripts for -contains used on string variables and verify each one is actually testing array membership — you may find hidden bugs waiting to surface.


