2

I have never got the -contains operator to work in Powershell I don't know why.

Here's an example of where it isn't working. I use -like in its place but I'd love it if you could tell me why this isn't working.

PS HKLM:\Software\Microsoft\Windows NT\CurrentVersion> (gp . P*).ProductName
Windows 10 Enterprise

PS HKLM:\Software\Microsoft\Windows NT\CurrentVersion> (gp . P*).ProductName -contains "Windows"
False

PS HKLM:\Software\Microsoft\Windows NT\CurrentVersion> (gp . P*).ProductName | gm | select TypeName | Get-Unique

TypeName     
--------     
System.String
3
  • you're looking for -match 'Windows' or -like '*Windows*', contains is for arrays only. Commented Sep 13, 2017 at 10:29
  • The -match operator, as far as I understand, is for working with regular expressions, which include the smaller subset of wildcards, so that will work as well. But if I wanted to just use the contains operator properly, how would I do that? My question is not how do I do this? but rather why does this never work for me and what am I doing wrong with this operator here? There are a 100 ways to do the thing. I could just call "The string Value".Contains() from the .NET Base Class Library. Commented Sep 13, 2017 at 10:36
  • Possible duplicate of PowerShell and the -contains operator Commented Sep 13, 2017 at 10:39

2 Answers 2

12

The -contains operator is not a string operator, but a collection containment operator:

'a','b','c' -contains 'b' # correct use of -contains against collection

From the about_Comparison_Operators help topic:

Type         Operator      Description
Containment  -contains     Returns true when reference value contained in a collection
             -notcontains  Returns true when reference value not contained in a collection
             -in           Returns true when test value contained in a collection
             -notin        Returns true when test value not contained in a collection

Usually you would use the -like string operator in PowerShell, which supports Windows-style wildcard matching (* for any number of any characters, ? for exactly one of any character, [abcdef] for one of a character set):

'abc' -like '*b*' # $true
'abc' -like 'a*' # $true

Another alternative is the -match operator:

'abc' -match 'b' # $true
'abc' -match '^a' # $true

For verbatim substring matching, you would want to escape any input pattern, since -match is a regex operator:

'abc.e' -match [regex]::Escape('c.e')

An alternative is to use the String.Contains() method:

'abc'.Contains('b') # $true

With the caveat that, unlike powershell string operators, it's case-sensitive.


String.IndexOf() is yet another alternative, this one allows you to override the default case-sensitivity:

'ABC'.IndexOf('b', [System.StringComparison]::InvariantCultureIgnoreCase) -ge 0

IndexOf() returns -1 if the substring is not found, so any non-negative return value can be interpreted as having found the substring.

Sign up to request clarification or add additional context in comments.

3 Comments

Ah! As I suspected. Your first line answered my question. Thank you. I should make some time for a thorough reading of the documentation.
@WaterCoolerv2 There's a lot of good stuff in the about_* help topics, I updated the answer with a table of containment operators from the about_Comparison_Operators document
That's right. I'm aware of them, @Mathias. Just haven't made the time to read through all of it carefully yet.
2

The '-contains' operator is best used for comparison to lists or arrays, e.g.

$list = @("server1","server2","server3")
if ($list -contains "server2"){"True"}
else {"False"}

output:

True

I'd suggest using '-match' instead for string comparisons:

$str = "windows"
if ($str -match "win") {"`$str contains 'win'"}
if ($str -match "^win") {"`$str starts with 'win'"}
if ($str -match "win$") {"`$str ends with 'win'"} else {"`$str does not end with 'win'"}
if ($str -match "ows$") {"`$str ends with 'ows'"}

output:

$str contains 'win'
$str starts with 'win'
$str does not end with 'win'
$str ends with 'ows'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.