PowerShell Where-Object Contains (With Examples)

To filter objects where a property contains some text, use Where-Object with the -like operator and wildcards on both sides. This returns every server whose name contains “SQL”:

$servers | Where-Object Name -like '*SQL*'

The -contains operator looks like the obvious choice, but it doesn’t check for text inside a string. That trips up almost everyone, so I’ll show you why below.

All the examples use this small list of servers. Paste it into your console first:

$servers = @(
    [pscustomobject]@{ Name = 'WEB01';  Role = 'Web server';      City = 'Dallas';  Tags = @('prod', 'iis') }
    [pscustomobject]@{ Name = 'WEB02';  Role = 'Web server';      City = 'Austin';  Tags = @('test', 'iis') }
    [pscustomobject]@{ Name = 'SQL01';  Role = 'SQL Server';      City = 'Dallas';  Tags = @('prod', 'sql') }
    [pscustomobject]@{ Name = 'APP-SQL02'; Role = 'App and SQL';  City = 'Denver';  Tags = @('prod', 'sql', 'app') }
    [pscustomobject]@{ Name = 'FILE01'; Role = 'File server';     City = 'Seattle'; Tags = @('prod') }
)

Output:

Name      Role        City    Tags
----      ----        ----    ----
WEB01     Web server  Dallas  prod, iis
WEB02     Web server  Austin  test, iis
SQL01     SQL Server  Dallas  prod, sql
APP-SQL02 App and SQL Denver  prod, sql, app
FILE01    File server Seattle prod

I tested every example in PowerShell 7.6 and Windows PowerShell 5.1.

Where-Object contains: filter with -like

Here’s the command from the top, with its output:

$servers | Where-Object Name -like '*SQL*'

Output:

Name      Role        City   Tags
----      ----        ----   ----
SQL01     SQL Server  Dallas {prod, sql}
APP-SQL02 App and SQL Denver {prod, sql, app}
PowerShell Where-Object contains text using the -like operator with wildcards
Where-Object with -like ‘*SQL*’ in PowerShell 7

-like ignores case, so '*sql*' finds the same servers. The * means “any characters”, which is why a match anywhere in the name counts.

Wildcards work the same way everywhere -like is used, as explained in the PowerShell -like operator.

Why does -contains return nothing?

This is the most common mistake with Where-Object:

$servers | Where-Object Name -contains 'SQL'
'Found: ' + @($servers | Where-Object Name -contains 'SQL').Count

Output:

Found: 0
Where-Object -contains returning no results for a substring in Windows PowerShell 5.1
-contains finds nothing (Windows PowerShell 5.1)

-contains is a collection operator. It asks “is this exact item in the list?”, not “does this text appear inside the string?”:

'SQL01' -contains 'SQL'               # a string is not a collection
@('SQL01', 'WEB01') -contains 'SQL01' # exact match of a whole item
@('SQL01', 'WEB01') -contains 'sql01' # case-insensitive

Output:

False
True
True

Use -contains when the property is a list, like the Tags column later in this article. For text inside a string, use -like or -match.

The .NET .Contains() method does check for a substring, but it’s case-sensitive, unlike PowerShell’s operators:

'SQL01'.Contains('SQL')
'SQL01'.Contains('sql')    # case-sensitive

Output:

True
False

Use a script block for more complex conditions

The short form (Where-Object Name -like '*SQL*') handles one condition. For two or more, use a script block with $_:

$servers | Where-Object { $_.Name -like '*sql*' -or $_.Role -like '*sql*' } |
    Select-Object Name, Role

Output:

Name      Role
----      ----
SQL01     SQL Server
APP-SQL02 App and SQL

I go deeper into this in Where-Object with multiple conditions.

Where-Object starts with

Put the wildcard only at the end to match the start of a string:

$servers | Where-Object Name -like 'WEB*' | Select-Object Name, City

Output:

Name  City
----  ----
WEB01 Dallas
WEB02 Austin

Does not start with

Swap in -notlike:

$servers | Where-Object Name -notlike 'WEB*' | Select-Object -ExpandProperty Name

Output:

SQL01
APP-SQL02
FILE01

Ends with

Move the wildcard to the front:

$servers | Where-Object Name -like '*01' | Select-Object -ExpandProperty Name

Output:

WEB01
SQL01
FILE01

Exclude items with -notlike

-notlike works with any pattern, not just “starts with”. This keeps servers whose role doesn’t mention “server”:

$servers | Where-Object Role -notlike '*server*' | Select-Object Name, Role

Output:

Name      Role
----      ----
APP-SQL02 App and SQL

Filter with regex using -match

When wildcards aren’t enough, -match takes a regular expression. This one keeps names that are WEB or FILE followed by exactly two digits:

$servers | Where-Object Name -match '^(WEB|FILE)\d{2}$' | Select-Object -ExpandProperty Name

Output:

WEB01
WEB02
FILE01

To match any of several words, separate them with |:

$servers | Where-Object Role -match 'SQL|File' | Select-Object Name, Role

Output: