1

I'm struggling with this code:

Get-Sensor -Name Ping | where {$_.Tags -like "Kat.A" -or $_.Tags -like "Kat.B" -or $_.Tags -like "Kat.C" -or $_.Tags -like "Kat.D"} | Select-Object Device, Tags

I get these values via. Connect-PrtgServer. The output data for this is:

DEVICENAME {Kat.C}
DEVICENAME {Kat.B, C_OS_Win}
DEVICENAME {Kat.A, pingsensor}
DEVICENAME {Kat.A}
DEVICENAME {Kat.A, pingsensor} DEVICENAME {Kat.D}
DEVICENAME {Kat.D, pingsensor} DEVICENAME {Kat.B}

In this case, I want the other way around. I want to use -notlike to get all object, which doesn't have a "Kat.A, Kat.B, Kat.C or Kat.B" Tag. So I changed the code to:

Get-Sensor -Name Ping | where {$_.Tags -notlike "Kat.A" -or $_.Tags -notlike "Kat.B" -or $_.Tags -notlike "Kat.C" -or $_.Tags -notlike "Kat.D"} | Select-Object Device, Tags

But here is problem, that I get more values than needed:

DEVICENAME {Kat.D, test}
DEVICENAME {Kat.C, sql}
DEVICENAME {Kat.D, domaincontroller}
DEVICENAME {pingsensor, memberserver}
DEVICENAME {pingsensor, memberserver}
DEVICENAME {pingsensor, memberserver}
DEVICENAME {pingsensor, memberserver}
DEVICENAME {Kat.C}

I only need those four devices/tags which starts with pingsensor, because they don't contain a Kat.

Thank you for your upcoming help guys.

Best regards :)

  • 1
    Please add all details directly as pure text into the question, images is a poor conveyer here. – hlovdal May 08 '23 at 12:14
  • 2
    Classic logic inversion. You want to use `-and` instead of `-or` - if a result you're trying to exclude is `Kat.A` then `-notlike 'Kat.B'` is still true – Mathias R. Jessen May 08 '23 at 12:18
  • With -and I also get more than the Kat. categories. – HorstSchlemmer12345 May 08 '23 at 12:36
  • 1
    Could try -notin Get-Sensor -Name Ping | Where-Object {$_.Tags -notin @("Kat.A","Kat.B","Kat.C","Kat.D") } | Select-Object Device, Tags – Grok42 May 08 '23 at 13:29
  • Doesn't work also. I really don't get why our attempts don't work. With -notin I get every Device with more than one tags. For example: DEVICENAME {KAT.D, test} all devices with DEVICENAME {KAT.A} are filtered. When I change to Get-Sensor -Name Ping | Where-Object {$_.Tags -notin @("Kat.A*","Kat.B*","Kat.C*","Kat.D*") } | Select-Object Device, Tags I get all devices. – HorstSchlemmer12345 May 08 '23 at 14:13
  • You use -like, but there's no * wildcards. You use select, but there's no property headers. – js2010 May 08 '23 at 14:58

1 Answers1

0

If this works:

$_.Tags -like "Kat.A" -or $_.Tags -like "Kat.B" -or $_.Tags -like "Kat.C" -or $_.Tags -like "Kat.D"`

and you want to negate it, enclose the expression in (...) and prepend -not:

-not ($_.Tags -like "Kat.A" -or $_.Tags -like "Kat.B" -or $_.Tags -like "Kat.C" -or $_.Tags -like "Kat.D")

However, since you're not using actual wildcard characters in your comparison patterns, there is no need for -like -just use -eq - or, preferably, given that $_.Tags seems to contain an array of values, use the -contains operator

-not ($_.Tags -contains "Kat.A" -or $_.Tags -contains "Kat.B" -or $_.Tags -contains "Kat.C" -or $_.Tags -contains "Kat.D")

Note, however, that if wildcard matching were truly needed, -contains wouldn't work.


Note:

  • Switching from ... -like ... -or ... to ... -notlike ... -and ... (analogously for -eq and -ne) is not the equivalent negation if the LHS operands are arrays, which seems to be the case for you.

  • The reason is that PowerShell's comparison operators act as filters with array-valued (list-like) LHS operands:

    • That is, with an array as the LHS, they return the sub-array of matching items rather than a Boolean ($true or $false).

    • Using an array as if it were a Boolean - which PowerShell lets you do implicitly, because it can quietly coerce any data type to a Boolean[1] - can have surprising results - see the example below.

# Define an array to serve as the LHS of a -like operation.
$tags = 'Kat.A', 'Kat.B'

# BOTH -like operations evaluate to $true in the implied Boolean context of `if`, 
# because they both return a non-empty subarray of matching elements.
if ($tags    -like 'Kat.A') { 'yes' }
if ($tags -notlike 'Kat.A') { 'yes' }

Somewhat counterintuitively, this outputs yes twice.

That is, the results of the array-filtering operations, when interpreted as Booleans, were both true, because in effect the two if conditionals were equivalent to:

  • [bool] @('Kat.A') -> $true
  • [bool] @('Kat.B') -> also $true

By contrast, the containment operators, -contains and its operands-reversed counterpart, -in, whose very purpose is to operate on arrays (list-like collections), always return a Boolean ($true or $false), so it is possible to properly negate
... -contains ... -or ... as ... -notcontains ... -and ...


[1] See the bottom section of this answer for a summary of the to-Boolean conversion rules.

mklement0
  • 382,024
  • 64
  • 607
  • 775