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.

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:

Name      Role
----      ----
SQL01     SQL Server
APP-SQL02 App and SQL
FILE01    File server

-notmatch is the opposite. This keeps every server whose name doesn’t start with WEB:

$servers | Where-Object Name -notmatch '^WEB' | Select-Object -ExpandProperty Name

Output:

SQL01
APP-SQL02
FILE01

For more patterns, see my PowerShell regex guide.

Make the match case-sensitive

-like and -match ignore case. Put a c in front (-clike, -cmatch) when case matters:

'-like  : ' + @($servers | Where-Object Name -like '*sql*').Count
'-clike : ' + @($servers | Where-Object Name -clike '*sql*').Count
'-cmatch: ' + @($servers | Where-Object Name -cmatch 'SQL').Count

Output:

-like  : 2
-clike : 0
-cmatch: 2

Where-Object in array: -in and -notin

To keep objects whose property equals any value in a list, use -in. It’s the same as “WHERE City IN (…)” in SQL:

$texas = 'Dallas', 'Austin', 'Houston'

$servers | Where-Object City -in $texas | Select-Object Name, City

Output:

Name  City
----  ----
WEB01 Dallas
WEB02 Austin
SQL01 Dallas
PowerShell Where-Object -in filtering by a list of values
Where-Object with -in in PowerShell 7

-notin keeps everything else:

$servers | Where-Object City -notin 'Dallas', 'Austin' | Select-Object Name, City

Output:

Name      City
----      ----
APP-SQL02 Denver
FILE01    Seattle

-in needs exact matches (case-insensitive). It won’t match part of a value, so use -match 'Dallas|Austin' for partial matches.

When the property is a list: use -contains

Here’s where -contains is the right tool. Tags holds several values, and I want every server tagged sql:

$servers | Where-Object Tags -contains 'sql' | Select-Object Name, @{ Name = 'Tags'; Expression = { $_.Tags -join ', ' } }

Output:

Name      Tags
----      ----
SQL01     prod, sql
APP-SQL02 prod, sql, app

Filter a list of strings

Everything above works on plain strings too. Inside the script block, $_ is the string itself:

$lines = 'INFO  Service started',
         'ERROR Could not reach SQL01',
         'WARN  Disk at 91%',
         'ERROR Login failed for svc_backup'

$lines | Where-Object { $_ -like 'ERROR*' }

Output:

ERROR Could not reach SQL01
ERROR Login failed for svc_backup

To search text inside files, use Select-String instead. I cover it in find text patterns with Select-String.

Filter files by name

The same operators filter files. Use -Filter first to narrow the list, then Where-Object for the rest:

Get-ChildItem -Path C:\psfaqs\Logs -Filter *.log |
    Where-Object Name -notlike 'sql*' |
    Select-Object -ExpandProperty Name

Output:

app.log
web.log

A faster option: the .Where() method

For data already in a variable, the .Where() method avoids the pipeline and is usually faster:

$servers.Where({ $_.City -eq 'Dallas' }).Name

Output:

WEB01
SQL01

Microsoft lists every operator in about_Comparison_Operators.

Frequently Asked Questions

How do I check if a string contains text in Where-Object?

Use -like with wildcards: Where-Object Name -like '*text*'. -contains won’t work, because it checks whole items in a collection.

What is the difference between -contains and -like in PowerShell?

-like matches a string against a wildcard pattern. -contains checks whether a collection includes an exact value, for example @('a','b') -contains 'a'.

How do I filter where a value is in an array?

Use -in: Where-Object City -in 'Dallas', 'Austin'. Use -notin to exclude those values.

How do I use regex with Where-Object?

Use -match with a pattern, for example Where-Object Name -match '^WEB\d+$'. Use -notmatch to exclude matches.

Is Where-Object -like case-sensitive?

No. Use -clike or -cmatch for a case-sensitive filter.

Continue with these Where-Object guides: