powershellactive-directorywhere-clause

Powershell where-object complex logic


I am having trouble coming up with a way to do complex logic using the where-object in PowerShell

I have the following code, but separating the and from the ORs is not working as intended.

Get-ADComputer -Filter * | Where-Object {
    ($_.Enabled) -and
    (($_.DistinguishedName -contains 'world') -or
    ($_.DistinguishedName -contains 'foo')) -and
    (($_.SID -contains 'bar') -or
    ($_.SID -contains 'something else'))
}

If I do this in c# I get results, but in powershell I do not.

Any thoughts on how to get around this?

TIA


Solution

  • The main issue is very likely with -contains, this is the operator you would use to check whether an item exists in an array, for example:

    'apple', 'banana', 'pineapple' -contains 'apple'
    
    # True
    

    This operator does not work in partial matches, only exact ones. For partial matches you could use -like or, the recommended one in this case would be the -match operator with a regex OR pattern:

    Get-ADComputer -Filter 'enabled -eq $true' | Where-Object {
        $_.DistinguishedName -match 'world|foo' -and
        $_.SID -match 'bar|something else'
    }
    

    Using -like the condition becomes very similar as what you currently have, however you do need the * wildcards (for the partial match), no parentheses are needed:

    Get-ADComputer -Filter 'enabled -eq $true' | Where-Object {
        $_.DistinguishedName -like '*world*' -or $_.DistinguishedName -like '*foo*' -and
        $_.SID -like '*bar*' -or $_.SID -like '*something else*'
    }
    

    If Where-Object isn't performing well (it can be slow), you might consider a more classic approach using foreach and if conditions:

    $result = foreach ($computer in Get-ADComputer -Filter 'enabled -eq $true') {
        if ($computer.DistinguishedName -match 'World|Foo' -and $computer.SID -match 'bar|something else') {
            $computer
        }
    }