Reputation: 11
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 :)
Upvotes: 1
Views: 935
Reputation: 437042
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.
Upvotes: 0