Search code examples
powershellpowershell-4.0

Combine multiple logical operators


Is there a way to combine parameters for multiple logical operators in a where statement?

Basically I have a statement like this:

<command chain> | where {$_.user.tostring() -ne "USER1" -and $_.user.tostring() -ne "USER2" -and $_.user.tostring() -ne "USER3"}

It's actually a fairly long chain, so I'd like to simplify it so that it becomes something like this:

<command chain> | where {$_.user.tostring() -ne {"USER1" -or "USER2" -or "USER3"}}

The above statement doesn't work, so any suggestions please on how to go about this?


Solution

  • You want to use this:

    where {$_.user.tostring() -notin ("USER1","USER2","USER3")}
    

    Or this:

    where {($_.user.tostring() -ne "USER1") -and ($_.user.tostring() -ne "USER2") -and ($_.user.tostring() -ne "USER3") }
    

    That's really about as simple as you can get. The boolean operators should, in general, only be used to combine comparison operators (or other things you know represent boolean values).


    Your code here:

    where {$_.user.tostring() -ne {"USER1" -or "USER2" -or "USER3"}}
    

    This is basically nonsense. It's always going to evaluate to true. {"USER1" -or "USER2" -or "USER3"} is of datatype ScriptBlock.

    PS C:\> ({"USER1" -or "USER2" -or "USER3"}).GetType().FullName
    System.Management.Automation.ScriptBlock
    

    I believe PowerShell will cast this to a string, but even if it gets cast to a string, it's still not evaluated as a boolean expression:

    PS C:> ({"USER1" -or "USER2" -or "USER3"}).ToString()
    "USER1" -or "USER2" -or "USER3"
    

    That's going to evaluate to True unless the user is literally '"USER1" -or "USER2" -or "USER3"'

    If you changed it so that it was a parenthetic expression instead of a script block:

    where {$_.user.tostring() -ne ("USER1" -or "USER2" -or "USER3")}
    

    Then it would always be true. ("USER1" -or "USER2" -or "USER3") is of type Boolean, and will always have the value of true.

    PS C:\> ("USER1" -or "USER2" -or "USER3")
    True
    

    So you're basically running:

    where {$_.user.tostring() -ne $true }
    

    Again, even if PowerShell converts everything to a string like I think it will, it's pretty unlikely you've got a user named "True". So this will always be true.