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

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

PowerShell Tips Editor 1 min read
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 -match for 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 $false because -contains checks 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 -cmatch to 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.

Send-Item -To