0

I found this function I'd like to use in a script I'm writing, but it keeps coming back $false when I can see an account is in a group and I can't figure out why?

function Check-IsGroupMember{

Param($user,$grp)

$strFilter = "(&(objectClass=Group)(name=" + $grp +"))"

$objDomain = New-Object System.DirectoryServices.DirectoryEntry

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
 $objSearcher.SearchRoot = $objDomain
 $objSearcher.PageSize = 1000
 $objSearcher.Filter = $strFilter
 $objSearcher.SearchScope = "Subtree"

$colResults = $objSearcher.FindOne()

$objItem = $colResults.Properties
 ([string]$objItem.member).contains($user)

}
Usage:

Check-IsGroupMember "name of user" "DomainAdmins"
MarcGel
  • 299
  • 6
  • 20
  • Is the group that user's primary group? – briantist Oct 30 '15 at 21:06
  • Probably not, but I was hoping to use this for any type of group? – MarcGel Oct 30 '15 at 21:16
  • Looking closer, it seems like the way you're doing it would work anyway, I think (searching the group's member list for a user rather than looking at the member of property of the user). – briantist Oct 30 '15 at 21:18
  • Are you using the user's name as it would appear in their Distinguished Name when you search? The results from that search are a collection of the member's distinguishedname strings, so you'd have to search for something that would appear within that. – TheMadTechnician Oct 30 '15 at 21:39
  • Hmm, yes DN seems to work, but seems to come back false on a very large group we have called AllUsers (22k) should I increase the pagesize? – MarcGel Oct 30 '15 at 21:48

1 Answers1

1

$objItem.member contains the DistinguishedName value of each principal who is a member of the group.

Even though the proper name of a person might be John Doe, the common name of the user account object may still be Doe, John, John G. Doe or anything else. This means that Contains() check (which is just a simple substring search) is not guaranteed to work as you expect.

The only real way to check is to either run another search for the user to find his/her DistinguishedName.

Personally, I would go for the AD PowerShell module from RSAT, rather than using a DirectorySearcher:

function Test-GroupMembership 
{
  Param(
    [string]$UserName,
    [string]$GroupName
  )

  $User  = Get-ADUser -Identity $UserName
  $Group = Get-ADGroup -Identity $GroupName -Properties member

  $Group.member -contains $User.DistinguishedName
}

If size limit is your problem, you can use the DirectoryServer to retrieve a ranged result of the member attribute:

function Test-GroupMembership 
{
  [CmdletBinding()]
  Param(
    [string]$UserName,
    [string]$GroupName
  )

  # Fetch User
  $User = Get-ADUser -Identity $UserName

  # return on failure
  if(-not $User){
    Write-Error -Message ('User "{0}" not found' -f $GroupName)
    return $false
  }

  # Use DirectorySearcher to retrieve ranged member attribute
  $GroupSearcher = '' -as [adsisearcher]
  $GroupSearcher.Filter = '(&(objectClass=group)(name={0}))' -f $GroupName
  $GroupSearcher.SearchScope = 'Subtree'
  $GroupSearcher.SearchRoot = '' -as [adsi]

  # AD reponds with at least 1500 values per multi-value attribute since Windows Server 2003
  $Start = 1
  $Range = 1500
  $GroupMembers = @()

  $HasMoreMembers = $false

  # Keep retrieving member values until we've got them all
  do{

    # Use range operator to "page" values
    # Ref: https://msdn.microsoft.com/en-us/library/aa367017(v=vs.85).aspx
    $RangedMember = 'member;range={0}-{1}' -f $Start,$($Start + $Range - 1)
    $GroupSearcher.PropertiesToLoad.Add($RangedMember) | Out-Null

    # Retrieve group        
    $Group = $GroupSearcher.FindOne()

    # return on failure
    if(-not $Group) {
      Write-Error -Message ('Group "{0}" not found' -f $GroupName)
      return $false
    }

    # If we've reached the end of the member list, 
    # AD will return a property where the upper range
    # value is *, so it might not be the same property 
    # name we specified in PropertiesToLoad
    $ReturnedMember = @($Group.Properties.PropertyNames) -like 'member;*'

    # Add all members to the $GroupMembers variable
    foreach($member in $Group.Properties."$ReturnedMember") { 
      # Test if user is in the member list
      if($member -eq $User.DistinguishedName){
        return $true
      }
    }

    # If we've reached the end, exit the loop
    if($ReturnedMember -eq $RangedPropertyName){
      $HasMoreMembers = $true
    }

  } while ($HasMoreMembers)

  # User wasn't found
  return $false
}

To provide a bit of consistency in user experience, please use Approved Verbs for command names in PowerShell (eg. Test-* instead of Check-*)

[adsisearcher] is a type accelerator for the DirectorySearcher class

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • I'm not sure I understand? Is there a way to guarantee the function finds a specific user that in a specific group you're searching for?? I'm trying the DN and SamAccountName and groups I know my account is in or not in and getting very inconsistent results. – MarcGel Oct 30 '15 at 22:03
  • @MarcGel Updated the answer. I still find this approach sub-optimal though. Is there a reason you're not using the RSAT Active Directory PowerShell Module (`Get-ADUser`, `Get-ADGroup` etc.)? – Mathias R. Jessen Oct 30 '15 at 22:04
  • I'd use those if it were not for the size limits. So, are you adding another function then for the distinguished name? Then possibly combine the functions? What is the most optimal solution? Thanks – MarcGel Oct 30 '15 at 22:27
  • @MarcGel if the size limit is the issue here, non of the above will work, you'll need to use the `range` operator – Mathias R. Jessen Oct 30 '15 at 22:35
  • Thanks a bunch Mathias! Your Test-GroupMembership function seems to work on even our very large groups. Why do these cmdlets work in a function but not outside of one? At least it seems that way as I've gotten "Reached Max Size Limit" errors on those before? – MarcGel Oct 30 '15 at 22:41
  • @MarcGel Sure you're testing against the same groups? Added an example utilizing the range operator – Mathias R. Jessen Oct 30 '15 at 23:19