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"
$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