1

I'm trying to filter objects that don't contain the string "C: \ Windows" in their path but the filtering isn't working well with $_.PathName parameter.

function unquotedPath {
    $unquotedPaths = Get-WmiObject -Class Win32_Service | Where-Object {$_.StartMode -eq "Auto"  -and $_.PathName -notcontains "C:\WINDOWS\"} | Select-Object -Property Name,DisplayName,PathName,StartMode | Out-String
    foreach ($unquotedPath in $unquotedPaths) {
        Write-Host $unquotedPath -ForegroundColor Green
    }
    
}
Paolo
  • 21,270
  • 6
  • 38
  • 69
Estiwer
  • 163
  • 1
  • 7
  • 4
    -notcontains is a collection operator. See https://stackoverflow.com/questions/18877580/powershell-and-the-contains-operator – dugas Dec 23 '21 at 16:33
  • 1
    and `| Out-String` makes it a single string object... – iRon Dec 23 '21 at 16:34
  • Im using Out-String to get a better output format it doesn't change the filtering anyways – Estiwer Dec 23 '21 at 16:37
  • In short: [`-contains` / `-notcontains`](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Comparison_Operators#-contains-and--notcontains) are _collection operators_: they test if the LHS object is _equal in full_ to at least one element of the RHS collection. They are not to be confused with the `.Contains()` .NET _method_ for _substring matching_. While PowerShell has no equivalent operator for _literal_ substring matching, you can use `-like` with _wildcard expressions_ or `-match` with _regular expressions_, both of which are case-_insensitive_. – mklement0 Dec 23 '21 at 17:10
  • 1
    To close the tangent re `Out-String`: What @iRon is trying to say is that `$unquotedPaths` will receive a _single_ (multi-line) output string across all filtered objects, so your foreach` loop will be entered (at most) _once_. Omitting the loop and using `Write-Host $unquotedPaths -ForegroundColor Green` instead would have the same effect. – mklement0 Dec 23 '21 at 17:38

2 Answers2

2

-notcontains is a collection operator. See helpful post at: PowerShell and the -contains operator

You can use:

Get-WmiObject -Class Win32_Service | Where-Object {$_.StartMode -eq "Auto" -and !$_.PathName.Contains('C:\WINDOWS\')} 
dugas
  • 12,025
  • 3
  • 45
  • 51
  • 1
    The link is helpful - though I think submitting it as part of a duplicate close vote would have sufficed. Note that `.Contains()` - unlike PowerShell's operators - is case-_sensitive_; _invariably_ so in Windows PowerShell, and _by default_ in PowerShell (Core) 7+. – mklement0 Dec 23 '21 at 17:32
  • 1
    @mklement0 - considered that, noted, thanks. – dugas Dec 23 '21 at 17:33
2

Instead of using -notcontains, use -notlike:

Get-WmiObject -Class Win32_Service | Where-Object {$_.StartMode -eq "Auto"  -and $_.PathName -notlike "*C:\WINDOWS\*"}

.. or -notmatch:

Get-WmiObject -Class Win32_Service | Where-Object {$_.StartMode -eq "Auto"  -and $_.PathName -notmatch "^.*C:\\WINDOWS\\"}

-notcontains is for checking whether the right hand argument (an object) matches one of the elements in the left side argument (a set). See more here.

-notlike is for checking whether the element does not match a specific pattern. See more here.

-notmatch is like -notlike but allows for regex expressions, so its more powerful. See more here.

Paolo
  • 21,270
  • 6
  • 38
  • 69