john
john

Reputation: 187

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

Upvotes: 0

Views: 554

Answers (2)

Lee_Dailey
Lee_Dailey

Reputation: 7489

this is not an Answer - so please let me know when you have read it so that i can delete it.

this is your code with more informative indentation, with the needless extra parens removed, and with spaces around the operators.

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

note that the -contains operator is NOT for strings ... it is for membership in a collection. if you want to test against strings, use -match, or .Contains(), or -like with wildcards.

Upvotes: 2

Santiago Squarzon
Santiago Squarzon

Reputation: 61293

This is how you would perform your query using AD PS Module:

Get-ADComputer -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)"|where-object{
    $_.DistinguishedName -match 'World|Foo' -and $_.SID -match 'bar|something else'
}
  • -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)" = Enabled Computer Object
  • -match allows the use of regex, you can use the pipeline as OR.

-contains is the operator you would use to lookup an item on an array. Example:

PS /> @(
'apple'
'banana'
'pineapple'
) -contains 'apple'

True

In addition, as Dave Wyatt pointed out in a nice post on powershell.org a while ago, you might want to avoid where-object whenever possible since it's the slowest way to filter collections. It's only advantages are the low memory consumption and pipeline streaming. Here are a few examples of faster efficient code:

#Example 1:
$computers=Get-ADComputer -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)"
$collection=[system.collections.generic.list[Microsoft.ActiveDirectory.Management.ADComputer]]::new()

foreach($computer in $computers)
{
    if($computer.DistinguishedName -match 'World|Foo' -and $computer.SID -match 'bar|something else')
    {
        $collection.add($computer)
    }
}

#Example 2:
filter myFilter{
    if($_.DistinguishedName -match 'World|Foo' -and $_.SID -match 'bar|something else')
    {
        $_
    }
}

$computers=Get-ADComputer -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)"|myFilter

#Example 3
$computers=(Get-ADComputer -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)").where({
    $_.DistinguishedName -match 'World|Foo' -and $_.SID -match 'bar|something else'  
})

There is plenty on information on the different ways of filtering Collections on PowerShell and their pros / cons on Google.

Upvotes: 3

Related Questions