about_Comparison_Operators

Short description

The comparison operators in PowerShell can either compare two values or filter elements of a collection against an input value.

Long description

Comparison operators let you compare values or finding values that match specified patterns. PowerShell includes the following comparison operators:

Equality

  • -eq, -ieq, -ceq - equals
  • -ne, -ine, -cne - not equals
  • -gt, -igt, -cgt - greater than
  • -ge, -ige, -cge - greater than or equal
  • -lt, -ilt, -clt - less than
  • -le, -ile, -cle - less than or equal

Matching

  • -like, -ilike, -clike - string matches wildcard pattern
  • -notlike, -inotlike, -cnotlike - string doesn't match wildcard pattern
  • -match, -imatch, -cmatch - string matches regex pattern
  • -notmatch, -inotmatch, -cnotmatch - string doesn't match regex pattern

Replacement

  • -replace, -ireplace, -creplace - replaces strings matching a regex pattern

Containment

  • -contains, -icontains, -ccontains - collection contains a value
  • -notcontains, -inotcontains, -cnotcontains - collection doesn't contain a value
  • -in - value is in a collection
  • -notin - value isn't in a collection

Type

  • -is - both objects are the same type
  • -isnot - the objects aren't the same type

Common features

String comparisons are case-insensitive unless you use the explicit case-sensitive operator. To make a comparison operator case-sensitive, add a c after the -. For example, -ceq is the case-sensitive version of -eq. To make the case-insensitivity explicit, add an i after -. For example, -ieq is the explicitly case-insensitive version of -eq.

String comparisons use the InvariantCulture for both case-sensitive and case-insensitive comparisons. The comparisons are between unicode code points and don't use culture-specific collation ordering. The results are the same regardless of the current culture.

When the left-hand value in the comparison expression is a scalar value, the operator returns a Boolean value. When the left-hand value in the expression is a collection, the operator returns the elements of the collection that match the right-hand value of the expression. Right-hand values are always treated as singleton instances, even when they're collections. The comparison operators can't effectively compare collections to collections.

If there are no matches in the collection, comparison operators return an empty array. For example:

$a = (1, 2) -eq 3
$a.GetType().Name
$a.Count
Object[]
0

There are a few exceptions:

  • The containment and type operators always return a Boolean value
  • The -replace operator returns the replacement result
  • The -match and -notmatch operators also populate the $Matches automatic variable unless the left-hand side of the expression is a collection.

Equality operators

-eq and -ne

When the left-hand side is scalar, -eq returns True if the right-hand side is equivalent, otherwise, -eq returns False. -ne does the opposite; it returns False when both sides are equivalent; otherwise, -ne returns True.

Example:

2 -eq 2                 # Output: True
2 -eq 3                 # Output: False
"abc" -eq "abc"         # Output: True
"abc" -eq "abc", "def"  # Output: False
"abc" -ne "def"         # Output: True
"abc" -ne "abc"         # Output: False
"abc" -ne "abc", "def"  # Output: True

When the left-hand side is a collection, -eq returns those members that match the right-hand side, while -ne filters them out.

Example:

1,2,3 -eq 2             # Output: 2
"abc", "def" -eq "abc"  # Output: abc
"abc", "def" -ne "abc"  # Output: def

These operators process all elements of the collection. Example:

"zzz", "def", "zzz" -eq "zzz"
zzz
zzz

The equality operator can compare objects of different types. It's important to understand that the value on the right-hand side of the comparison can be converted to the type of the left-hand side value for comparison.

For example, the string '1.0' is converted to an integer to be compared to the value 1. This example returns True.

PS> 1 -eq '1.0'
True

In this example, the value 1 is converted to a string to be compared to string '1.0'. This example returns False.

PS> '1.0' -eq 1
False

The equality operators accept any two objects, not just a scalar or collection. But the comparison result isn't guaranteed to be meaningful for the end-user. The following example demonstrates the issue.

class MyFileInfoSet {
    [String]$File
    [Int64]$Size
}
$a = [MyFileInfoSet]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$b = [MyFileInfoSet]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$a -eq $b
False

In this example, we created two objects with identical properties. Yet, the equality test result is False because they're different objects. To create comparable classes, you need to implement System.IEquatable<T> in your class. The following example demonstrates the partial implementation of a MyFileInfoSet class that implements System.IEquatable<T> and has two properties, File and Size. The Equals() method returns True if the File and Size properties of two MyFileInfoSet objects are the same.

class MyFileInfoSet : System.IEquatable[Object] {
    [String]$File
    [Int64]$Size

    [bool] Equals([Object] $obj) {
        return ($this.File -eq $obj.File) -and ($this.Size -eq $obj.Size)
    }
}
$a = [MyFileInfoSet]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$b = [MyFileInfoSet]@{File = "C:\Windows\explorer.exe"; Size = 4651032}
$a -eq $b
True

A prominent example of comparing arbitrary objects is to find out if they're null. But if you need to determine whether a variable is $null, you must put $null on the left-hand side of the equality operator. Putting it on the right-hand side doesn't do what you expect.

For example, let $a be an array containing null elements:

$a = 1, 2, $null, 4, $null, 6

The following tests that $a isn't null.

$null -ne $a
True

The following, however, filers out all null elements from $a:

$a -ne $null # Output: 1, 2, 4, 6
1
2
4
6

-gt, -ge, -lt, and -le

-gt, -ge, -lt, and -le behave very similarly. When both sides are scalar they return True or False depending on how the two sides compare:

Operator Returns True when...
-gt The left-hand side is greater
-ge The left-hand side is greater or equal
-lt The left-hand side is smaller
-le The left-hand side is smaller or equal

In the following examples, all statements return True.

8 -gt 6  # Output: True
8 -ge 8  # Output: True
6 -lt 8  # Output: True
8 -le 8  # Output: True

Note

In most programming languages the greater-than operator is >. In PowerShell, this character is used for redirection. For details, see about_Redirection.

When the left-hand side is a collection, these operators compare each member of the collection with the right-hand side. Depending on their logic, they either keep or discard the member.

Example:

$a=5, 6, 7, 8, 9

Write-Output "Test collection:"
$a

Write-Output "`nMembers greater than 7"
$a -gt 7

Write-Output "`nMembers greater than or equal to 7"
$a -ge 7

Write-Output "`nMembers smaller than 7"
$a -lt 7

Write-Output "`nMembers smaller than or equal to 7"
$a -le 7
Test collection:
5
6
7
8
9

Members greater than 7
8
9

Members greater than or equal to 7
7
8
9

Members smaller than 7
5
6

Members smaller than or equal to 7
5
6
7

These operators work with any class that implements System.IComparable.

Examples:

# Date comparison
[DateTime]'2001-11-12' -lt [DateTime]'2020-08-01' # True

# Sorting order comparison
'a' -lt 'z'           # True; 'a' comes before 'z'
'macOS' -ilt 'MacOS'  # False
'MacOS' -ilt 'macOS'  # False
'macOS' -clt 'MacOS'  # True; 'm' comes before 'M'

The following example demonstrates that there is no symbol on an American QWERTY keyboard that gets sorted after 'a'. It feeds a set containing all such symbols to the -gt operator to compare them against 'a'. The output is an empty array.

$a=' ','`','~','!','@','#','$','%','^','&','*','(',')','_','+','-','=',
   '{','}','[',']',':',';','"','''','\','|','/','?','.','>',',','<'
$a -gt 'a'
# Output: Nothing

If the two sides of the operators aren't reasonably comparable, these operators raise a non-terminating error.

Matching operators

The matching operators (-like, -notlike, -match, and -notmatch) find elements that match or don't match a specified pattern. The pattern for -like and -notlike is a wildcard expression (containing *, ?, and [ ]), while -match and -notmatch accept a regular expression (Regex).

The syntax is:

<string[]> -like    <wildcard-expression>
<string[]> -notlike <wildcard-expression>
<string[]> -match    <regular-expression>
<string[]> -notmatch <regular-expression>

When the input of these operators is a scalar value, they return a Boolean value.

When the input is a collection of values, each item in the collection is converted to a string for comparison. The -match and -notmatch operators return any matching and non-matching members respectively. However, the -like and -notlike operators return the members as strings. The string returned for a member of the collection by -like and -notlike is the string the operator used for the comparison and is obtained by casting the member to a string.

-like and -notlike

-like and -notlike behave similarly to -eq and -ne, but the right-hand side could be a string containing wildcards.

Example:

"PowerShell" -like    "*shell"           # Output: True
"PowerShell" -notlike "*shell"           # Output: False
"PowerShell" -like    "Power?hell"       # Output: True
"PowerShell" -notlike "Power?hell"       # Output: False
"PowerShell" -like    "Power[p-w]hell"   # Output: True
"PowerShell" -notlike "Power[p-w]hell"   # Output: False

"PowerShell", "Server" -like "*shell"    # Output: PowerShell
"PowerShell", "Server" -notlike "*shell" # Output: Server

-match and -notmatch

-match and -notmatch use regular expressions to search for pattern in the left-hand side values. Regular expressions can match complex patterns like email addresses, UNC paths, or formatted phone numbers. The right-hand side string must adhere to the regular expressions rules.

Scalar examples:

# Partial match test, showing how differently -match and -like behave
"PowerShell" -match 'shell'        # Output: True
"PowerShell" -like  'shell'        # Output: False

# Regex syntax test
"PowerShell" -match    '^Power\w+' # Output: True
'bag'        -notmatch 'b[iou]g'   # Output: True

If the input is a collection, the operators return the matching members of that collection.

Collection examples:

"PowerShell", "Super PowerShell", "Power's hell" -match '^Power\w+'
# Output: PowerShell

"Rhell", "Chell", "Mel", "Smell", "Shell" -match "hell"
# Output: Rhell, Chell, Shell

"Bag", "Beg", "Big", "Bog", "Bug"  -match 'b[iou]g'
#Output: Big, Bog, Bug

"Bag", "Beg", "Big", "Bog", "Bug"  -notmatch 'b[iou]g'
#Output: Bag, Beg

-match and -notmatch support regex capture groups. Each time they run on scalar input, and the -match result is True, or the -notmatch result is False, they overwrite the $Matches automatic variable. $Matches is a Hashtable that always has a key named '0', which stores the entire match. If the regular expression contains capture groups, the $Matches contains additional keys for each group.

It's important to note that the $Matches hashtable contains only the first occurrence of any matching pattern.

Example:

$string = 'The last logged on user was CONTOSO\jsmith'
$string -match 'was (?<domain>.+)\\(?<user>.+)'

$Matches

Write-Output "`nDomain name:"
$Matches.domain

Write-Output "`nUser name:"
$Matches.user
True

Name                           Value
----                           -----
domain                         CONTOSO
user                           jsmith
0                              was CONTOSO\jsmith

Domain name:
CONTOSO

User name:
jsmith

When the -match result is False, or the -notmatch result is True, or when the input is a collection, the $Matches automatic variable isn't overwritten. Consequently, it will contain the previously set value, or $null if the variable hasn't been set. When referencing $Matches after invoking one of these operators, consider verifying that the variable was set by the current operator invocation using a condition statement.

Example:

if ("<version>1.0.0</version>" -match '<version>(.*?)</version>') {
    $Matches
}

For details, see about_Regular_Expressions and about_Automatic_Variables.

Replacement operator

Replacement with regular expressions

Like -match, the -replace operator uses regular expressions to find the specified pattern. But unlike -match, it replaces the matches with another specified value.

Syntax:

<input> -replace <regular-expression>, <substitute>

The operator replaces all or part of a value with the specified value using regular expressions. You can use the operator for many administrative tasks, such as renaming files. For example, the following command changes the file name extensions of all .txt files to .log:

Get-ChildItem *.txt | Rename-Item -NewName { $_.name -replace '\.txt$','.log' }

By default, the -replace operator is case-insensitive. To make it case sensitive, use -creplace. To make it explicitly case-insensitive, use -ireplace.

Examples:

"book" -ireplace "B", "C" # Case insensitive
"book" -creplace "B", "C" # Case-sensitive; hence, nothing to replace
Cook
book

Beginning in PowerShell 7.2, when the left-hand operand in a -replace operator statement isn't a string, that operand is converted to a string. PowerShell does a culture-insensitive string conversion.

For example, if your culture is set to French (fr), the culture-sensitive string conversion of value 1.2 is 1,2.

Prior to PowerShell 7.2:

PS> [cultureinfo]::CurrentCulture = 'fr'
PS> 1.2 -replace ','
12

In PowerShell 7.2 and later:

PS> [cultureinfo]::CurrentCulture = 'fr'
PS> 1.2 -replace ','
1.2

Regular expressions substitutions

It's also possible to use regular expressions to dynamically replace text using capturing groups, and substitutions. Capture groups can be referenced in the <substitute> string using the dollar sign ($) character before the group identifier.

In the following example, the -replace operator accepts a username in the form of DomainName\Username and converts to the Username@DomainName format:

$SearchExp = '^(?<DomainName>[\w-.]+)\\(?<Username>[\w-.]+)$'
$ReplaceExp = '${Username}@${DomainName}'

'Contoso.local\John.Doe' -replace $SearchExp, $ReplaceExp
John.Doe@Contoso.local

Warning

The $ character has syntactic roles in both PowerShell and regular expressions:

  • In PowerShell, between double quotation marks, it designates variables and acts as a subexpression operator.
  • In Regex search strings, it denotes end of the line.
  • In Regex substitution strings, it denotes captured groups. Be sure to either put your regular expressions between single quotation marks or insert a backtick (`) character before them.

For example:

$1 = 'Goodbye'

'Hello World' -replace '(\w+) \w+', "$1 Universe"
# Output: Goodbye Universe

'Hello World' -replace '(\w+) \w+', '$1 Universe'
# Output: Hello Universe

$$ in Regex denotes a literal $. This $$ in the substitution string to include a literal $ in the resulting replacement. For example:

'5.72' -replace '(.+)', '$ $1' # Output: $ 5.72
'5.72' -replace '(.+)', '$$$1' # Output: $5.72
'5.72' -replace '(.+)', '$$1'  # Output: $1

To learn more, see about_Regular_Expressions and Substitutions in Regular Expressions.

Substituting in a collection

When the <input> to the -replace operator is a collection, PowerShell applies the replacement to every value in the collection. For example:

"B1","B2","B3","B4","B5" -replace "B", 'a'
a1
a2
a3
a4
a5

Replacement with a script block

In PowerShell 6 and later, the -replace operator also accepts a script block that performs the replacement. The script block runs once for every match.

Syntax:

<String> -replace <regular-expression>, {<Script-block>}

Within the script block, use the $_ automatic variable to access the input text being replaced and other useful information. This variable's class type is System.Text.RegularExpressions.Match.

The following example replaces each sequence of three digits with the character equivalents. The script block runs for each set of three digits that needs to be replaced.

"072101108108111" -replace "\d{3}", {return [char][int]$_.Value}
Hello

Containment operators

The containment operators (-contains, -notcontains, -in, and -notin) are similar to the equality operators, except that they always return a Boolean value, even when the input is a collection. These operators stop comparing as soon as they detect the first match, whereas the equality operators evaluate all input members. In a very large collection, these operators return quicker than the equality operators.

-contains and -notcontains

Syntax:

<Collection> -contains <scalar-object>
<Collection> -notcontains <scalar-object>

These operators tell whether a set includes a certain element. -contains returns True when the right-hand side (scalar-object) matches one of the elements in the set. -notcontains returns False instead.

Examples:

"abc", "def" -contains "def"                  # Output: True
"abc", "def" -notcontains "def"               # Output: False
"Windows", "PowerShell" -contains "Shell"     # Output: False
"Windows", "PowerShell" -notcontains "Shell"  # Output: True
"abc", "def", "ghi" -contains "abc", "def"    # Output: False
"abc", "def", "ghi" -notcontains "abc", "def" # Output: True

More complex examples:

$DomainServers = "ContosoDC1","ContosoDC2","ContosoFileServer","ContosoDNS",
                 "ContosoDHCP","ContosoWSUS"
$thisComputer  = "ContosoDC2"

$DomainServers -contains $thisComputer
# Output: True

When the right-hand side operand is a collection, these operators convert the value to its string representation before comparing it to the left-hand side collection.

$a = "abc", "def"
"abc", "def", "ghi" -contains $a # Output: False

# The following statements are equivalent
$a, "ghi" -contains $a           # Output: True
"$a", "ghi" -contains $a         # Output: True
"abc def", "ghi" -contains $a    # Output: True

-in and -notin

Syntax:

<scalar-object> -in <Collection>
<scalar-object> -notin <Collection>

The -in and -notin operators were introduced in PowerShell 3 as the syntactic reverse of the of -contains and -notcontains operators. -in returns True when the left-hand side <scalar-object> matches one of the elements in the collection. -notin returns False instead.

The following examples do the same thing that the examples for -contains and -notcontains do, but they're written with -in and -notin instead.

"def" -in "abc", "def"                  # Output: True
"def" -notin "abc", "def"               # Output: False
"Shell" -in "Windows", "PowerShell"     # Output: False
"Shell" -notin "Windows", "PowerShell"  # Output: True
"abc", "def" -in "abc", "def", "ghi"    # Output: False
"abc", "def" -notin "abc", "def", "ghi" # Output: True

More complex examples:

$DomainServers = "ContosoDC1","ContosoDC2","ContosoFileServer","ContosoDNS",
                 "ContosoDHCP","ContosoWSUS"
$thisComputer  = "ContosoDC2"

$thisComputer -in $DomainServers
# Output: True

When the left-hand side operand is a collection, these operators convert the value to its string representation before comparing it to the right-hand side collection.

$a = "abc", "def"
$a -in "abc", "def", "ghi" # Output: False

# The following statements are equivalent
$a -in $a, "ghi"           # Output: True
$a -in "$a", "ghi"         # Output: True
$a -in "abc def", "ghi"    # Output: True

Type comparison

The type comparison operators (-is and -isnot) are used to determine if an object is a specific type.

Syntax:

<object> -is <type-reference>
<object> -isnot <type-reference>

Example:

$a = 1
$b = "1"
$a -is [int]           # Output: True
$a -is $b.GetType()    # Output: False
$b -isnot [int]        # Output: True
$a -isnot $b.GetType() # Output: True

See also