PowerShell AD module make checking group membership a trivial task. If I wanted to get the list of members for a group, I can use Get-ADGroupMember cmdlet. Problem with module is that, it's an 'extra' component on top of standard installation and if you will use it, you need to make sure that your script will have access to it. You may be using PowerShell as your logon/start-up script and your machines may not have the AD module. Yes, there are techniques remote-session techniques that can be employed to work around this but most would prefer to enumerate group members some other way.
One common method is using .Net classes, specifically "DirectoryServices.DirectorySearcher". I had a function that was using this class to enumerate group members, something like this:
function Get-GroupMembers { param ([string]$group) $searcher=new-object directoryservices.directorysearcher $filter="(&(objectClass=group)(cn=${group}))" $searcher.PageSize=1000 $searcher.Filter=$filter $result=$searcher.FindOne() $members = $result.properties.item("member") if ($members) { return $members } return $false }
I noticed that this stopped working for a specific group, and when I manually looked into the group properties, I found that "member" property of the group was empty. There was; however, another noticeable property that got populated instead: "member;range=0-1499".
Long story short, when members of a group exceed 1500, AD was populating that property instead of plain 'member' property and I needed to use a different technique called 'ranged retrieval'.
The main change is that we use 'PropertiesToLoad' property to feed $searcher object the range of members we would like to get and loop through them. When we give $searcher object an invalid range, it throws an error at us and we catch that to exit the loop. Here is the modified function.
## Return members of given AD group function Get-GroupMembers { param ([string]$group) if (-not ($group)) { return $false } $searcher=new-object directoryservices.directorysearcher $filter="(&(objectClass=group)(cn=${group}))" $searcher.PageSize=1000 $searcher.Filter=$filter $result=$searcher.FindOne() if ($result) { $members = $result.properties.item("member") ## Either group is empty or has 1500+ members if($members.count -eq 0) { $retrievedAllMembers=$false $rangeBottom =0 $rangeTop= 0 while (! $retrievedAllMembers) { $rangeTop=$rangeBottom + 1499 ##this is how it would show up in AD $memberRange="member;range=$rangeBottom-$rangeTop" $searcher.PropertiesToLoad.Clear() [void]$searcher.PropertiesToLoad.Add("$memberRange") $rangeBottom+=1500 try { ## should cause and exception if the $memberRange is not valid $result = $searcher.FindOne() $rangedProperty = $result.Properties.PropertyNames -like "member;range=*" $members +=$result.Properties.item($rangedProperty) # UPDATE - 2013-03-24 check for empty group if ($members.count -eq 0) { $retrievedAllMembers=$true } } catch { $retrievedAllMembers=$true ## we received all members } } } $searcher.Dispose() return $members } return $false }
6 comments:
Very good script. Howver, it seems to loop indefinitely if the group has 0 members :-(
I assumed try/catch would have caught that but apparently it did not. Added the check. Thank you!
This is exactly what I was looking for. Thanks a lot!
Z-man.
Can I get the same code using Java for more than 1500 members
plz help
Excellent work! I had looked at other scripts to do the same thing, but this one is the most straight forward and efficient. This goes into the library!
Post a Comment