memberof inconsistent filtering

Welcome Forums General PowerShell Q&A memberof inconsistent filtering

This topic contains 11 replies, has 5 voices, and was last updated by

 
Participant
3 weeks, 3 days ago.

  • Author
    Posts
  • #112519

    Participant
    Points: 0
    Rank: Member

    I want all AD users who are Not a member of "this group"

    neither of these work.

    get-aduser -filter * -properties memberof | ? memberof -notlike "*this group*"

    get-aduser -filter {memberof -notlike "*this group*"}

  • #112522

    Participant
    Points: 1
    Rank: Member

    you're close.
    try something like

    get-aduser -filter * -properties memberof|where-object -filterscript {$_.memberof -notlike "*groupname*"}
    
  • #112529

    Participant
    Points: 0
    Rank: Member

    thank you. I've never heard of filterscript, so now my obvious next question is: why do I have to use filterscript for memberof, when I don't have to use it for other AD attributes?

    get-aduser -filter * -properties samaccountname | ? samaccountname -like "*john.curtiss"

    works just fine.

    and: what other AD attributes require filterscript?

     

  • #112532

    Participant
    Points: 1
    Rank: Member

    well you're confusing 2 things.
    first, the aduser filter has some limitations on exactly what your allowed to use for filtering

    per get-aduser ms documentation:
    To search for and retrieve more than one user, use the Filter or LDAPFilter parameters. The Filter parameter uses the PowerShell Expression Language to write query strings for Active Directory. PowerShell Expression Language syntax provides rich type conversion support for value types received by the Filter parameter. For more information about the Filter parameter syntax, type Get-Help about_ActiveDirectory_Filter. If you have existing Lightweight Directory Access Protocol (LDAP) query strings, you can use the LDAPFilter parameter.

    I believe memberof is not a valid ldapfilter, so what we actually do is return every user, and their memberof value. we pipe those into the where-object powershell cmdlet. thats where the -filterscript comes in.
    technnically i don't have to call out the -filterscript but i wanted to use the verbose process so you could see exactly what happened.

    documentation for where-object is here:
    https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/where-object?view=powershell-6

  • #112543

    Participant
    Points: 0
    Rank: Member

    actually I take it back, don't think any of these are working...

    #count all users in the OU, returns 618
    
    (get-aduser -searchbase $searchbase -filter * | ? {$_.distinguishedname -notlike "*service accounts*"}).count
     
    
    #count all users in the OU, in the group, returns 252
    
    (get-aduser -searchbase $searchbase -filter * -Properties memberof | ? {$_.distinguishedname -notlike "*service accounts*" -and $_.memberof -like $group}).count
     
    
    #count all users in the OU, NOT in the group, returns 602
    
    (get-aduser -searchbase $searchbase -filter * -Properties memberof | ? {$_.distinguishedname -notlike "*service accounts*" -and $_.memberof -notlike $group}).count
    
    
    #count all users in the OU, NOT in the group, using filterscript, returns 602
    
    (get-aduser -searchbase $searchbase -filter * -Properties memberof | ? -filterscript {$_.distinguishedname -notlike "*service accounts*" -and $_.memberof -notlike $group}).count 
    
    

    I have the wildcards included in the string assigned to the $group variable. if I count all users in the OU, I get 618. if I count all users in the OU who ARE in the group, I get 252, which is also confirmed by get-adgroupmember. if I count all users in the OU who ARE NOT in the group, I get 602, whether or not I use filterscript. so if there are only 618 users in the OU, how can 252 of them be in the group and 602 of them not be in the group?

  • #112853

    Participant
    Points: 0
    Rank: Member

    help?

  • #112858

    Participant
    Points: 37
    PublishedHelping Hand
    Rank: Member

    So, as for your original query...

    I want all AD users who are Not a member of "this group"

    neither of these work.

    get-aduser -filter * -properties memberof | ? memberof -notlike "*this group*"
    get-aduser -filter {memberof -notlike "*this group*"}

    There are a half dozen ways to get this information. Some more direct than others. So, my question is on the more direct way to address your use case. Why are you not using...

    Get-ADGroupMember
    

    … since it's specific goal is to return users of the group(s) specified directly?
    Of course any user not in the list returned, well you know. You can use this list to compare / match, etc... against ADDS all users list via Get-ADUser.

    # Total AD users
    (Get-ADUser -Filter *).Count
    # 46
    
    # Users in the group
    ((Get-ADUser -Filter *).SamAccountName | 
    % {If($_ -eq $((Get-ADGroupMember $group).SamAccountName)){$_}}).Count
    # 1
    
    # Users not in the group
    ((Get-ADUser -Filter *).SamAccountName | 
    % {If($_ -ne $((Get-ADGroupMember $group).SamAccountName)){$_}}).Count
    # 45
    
    # This
    
    Clear-Host
    # Return a group name by array index
    # Note - I am doing this to not how sensitive info in the post
    
    "Listing non-members of the group $TargetGroupName"
    $users = (Get-ADUser -Filter *).SamAccountName
    $group = $TargetGroupName = ((Get-ADGroup -Filter *).Name)[75]((Get-ADGroupMember -Identity 
    $members = (Get-ADGroupMember -Identity $TargetGroupName).SamAccountName
    
    ForEach ($user in $users) 
    {
        If ($members -contains $user) 
        {"$user exists in the group"} 
        Else 
        {Write-Warning -Message "$user not in the group"}
    }
    
    
    # Results
    
    ...
    WARNING: labuser001 not in the group
    labuser002 exists in the group
    WARNING: labuser003 not in the group
    …
    

    If you want to stick with the indirect memberof route, then you have to deal with that with more work and specificity and be cautious logic issues. I decided to give you an approach that should work for your use case, vs figuring out why you are getting the oddities you are seeing. Yet, it's always a matter of using the right tool for the right job, but even that is based on what you want to do/use/believe or trust.

  • #112861

    Participant
    Points: 0
    Rank: Member

    I guess it never occurred to me that the "memberof route" was the indirect one. I must be used to the one-liners

    get-aduser -filter * -properties [ad attribute] | ? [ad attribute] -notlike "*something*"

    and

    get-aduser -filter {[ad attribute] -notlike "*something*"}

    working well for me for other [ad attribute]s. so I expected to be able to one-liner this one.

    but (i think) I read somewhere that since memberof contains DistinguishedNames, it doesn't work with wildcards. which is kind of weird, since "where memberof -like $group" returns the correct number of members, but "where memberof notlike $group" doesn't work at all. but I just used the whole DN of the group, and a one-liner with contains or notcontains works correctly.

    get-aduser -filter * -properties memberof | ? memberof -notcontains "[dn of this group]"

    (contains and notcontains are not supported in a get-aduser -filter)

  • #112864

    Participant
    Points: 65
    Published
    Rank: Member
  • #112897

    Participant
    Points: 37
    PublishedHelping Hand
    Rank: Member

    No worries, and yes ADDS is very finicky about how you ask it for things. There are lots of articles on the web regarding it.

    As for this...

    whole DN of the group, and a one-liner with contains or notcontains works correctly.'

    … this is because without the fully qualifying, you are not bringing back a specific object but the needed for the select, so, it can't be parsed for what you were after.

  • #112900

    Participant
    Points: 0
    Rank: Member

    A Few things:

    First:

    The negative of a query is sometimes hard to do when dealing with logical operators.  Here is an option that will accept wildcards (regex).

    ## note that the memberof property does not include the user's primary group, so we may need to account for that.

     
    
    # define the search string
    
    #  can be any part of the full distinguishedName
    
    #    ( Group Name, OU Name, or part of CN path )
    
    $GroupName = "admins"
    
    Get-ADUser -filter * -properties memberof, primaryGroup | ForEach-Object {
    
    # initalize $MATCH to FALSE (NOT FOUND)
    
    $matchFlag = $false
    
     
    
    # memberOf of is a collection
    
    # PowerShell will implicitly expand ALL the Values in memberOf
    
    # and try to match the regex
    
    # if a match is found, set matchFlag to TRUE
    
    # *** using -MATCH because it accepts a regex (wildcard support)
    
    if ($_.memberof -match ".*$GroupName.*" ) {
    
    $matchFlag = $true
    
    }
    
     
    
    # this is a single value
    
    # checking PrimaryGroup for a match too
    
    if ($_.PrimaryGroup -match ".*$GroupName.*" ) {
    
    $matchFlag = $true
    
    }
    
     
    
    # if a match WAS found, then do nothing
    
    # if a match was NOT found, then put the current
    
    # object back out on the pipeline
    
    if (-not $matchFlag) {
    
    Write-Output $_
    
    }
    
    }
    
    

     

    Second:

    Test in your environment and break down what you are really looking for.

    In my sample, above, I'm pulling ALL AD users and then checking for a match.  How would this scale is you had 60,000 accounts and users were in 100 groups, on average?

    If you have the reverse; you can loop across the groups which have a member property, then perform similar logic.

     

    Lastly,

    This method deals with direct group assignment, if you need to account for recursive groups the you'll need to look into LDAP filter   memberOf:1.2.840.113556.1.4.1941:=

  • #112903

    Participant
    Points: 0
    Rank: Member

    A Few things:

    First:

    The negative of a query is sometimes hard to do when dealing with logical operators.

    Here is an option that will accept wildcards (regex).

    ## note that the memberof property does not include the user's primary group, so we may need to account for that.

     
    
    # define the search string
    #  can be any part of the full distinguishedName
    #    ( Group Name, OU Name, or part of CN path )
    $GroupName = "admins"
    Get-ADUser -filter * -properties memberof, primaryGroup | ForEach-Object {
        # initalize $MATCH to FALSE (NOT FOUND)
        $matchFlag = $false
     
        # memberOf of is a collection
        # PowerShell will implicitly expand ALL the Values in memberOf
        # and try to match the regex
        # if a match is found, set matchFlag to TRUE
        # *** using -MATCH because it accepts a regex (wildcard support)
        if ($_.memberof -match ".*$GroupName.*" ) {
            $matchFlag = $true
        }
     
        # this is a single value
        # checking PrimaryGroup for a match too
        if ($_.PrimaryGroup -match ".*$GroupName.*" ) {
            $matchFlag = $true
        }
     
        # if a match WAS found, then do nothing
        # if a match was NOT found, then put the current
        # object back out on the pipeline
        if (-not $matchFlag) {
            Write-Output $_
        }
    }
    
    

    Second:

    Test in your environment and break down what you are really looking for.

    In my sample, above, I'm pulling ALL AD users and then checking for a match.  How would this scale if you had 60,000 accounts and users were in 100 groups, on average?

    If you have the reverse; would it be better to loop across the groups, which have a member property, then perform similar logic to find the negative.

     

    Lastly:

    This method deals with direct group assignment, if you need to account for recursive groups the you'll need to look into LDAP filter   memberOf:1.2.840.113556.1.4.1941:=

You must be logged in to reply to this topic.