Get-NetGroup fails with Large > 1500 members
Meatballs1 opened this issue · 6 comments
Meatballs1 commented
The result I'm getting back is a count of 0 members :(
However net group "groupname" /domain brings back lots
http://itq.nl/get-more-than-1500-members-from-an-active-directory-group/
If the 'member' count is 0 we should check if there is a property member;range=0-1499
and then member;1500-2999
etc
Meatballs1 commented
This is what I ended up using:
$GroupSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://DC=BLAH,DC=COM")
$GroupSearcher.filter = "(&(objectClass=group)(name=Large Group))"
$GroupSearcher.PageSize = 500
$out = $GroupSearcher.FindOne()
if ($out.properties.member.count -eq 0) {
$retrievedAllMembers=$false
$rangeBottom =0
$rangeTop= 0
while (! $retrievedAllMembers) {
$rangeTop=$rangeBottom+1499
$memberRange="member;range=$rangeBottom-$rangeTop"
$GroupSearcher.PropertiesToLoad.Clear()
[void]$GroupSearcher.PropertiesToLoad.Add("$memberRange")
$rangeBottom+=1500
try {
$result = $GroupSearcher.FindOne()
$rangedProperty = $result.Properties.PropertyNames -like "member;range=*"
$results = $result.Properties.item($rangedProperty)
if ($results.count -eq 0) {
$retrievedAllMembers=$true
} else {
$results.count | Out-Host
$results | % {
$output = New-Object psobject
$properties = ([adsi]"LDAP://$_").Properties
$output | add-member Noteproperty 'sAMAccountName' $properties.sAMAccountName.value
$output | add-member Noteproperty 'mail' $properties.mail.value
$output | Out-File -Append -FilePath out.txt
}
}
} catch [System.Management.Automation.MethodInvocationException] {
$retrievedAllMembers=$true
}
}
}
A version of this would be useful as a function that Get-NetGroup could call if member.count == 0
Meatballs1 commented
Would also had to look at recursion...
Meatballs1 commented
Diff looks summat like:
if ($GroupSearcher){
$GroupSearcher.PageSize = 200
$GroupSearcher.FindAll() | % {
try{
$GroupFoundName = $_.properties.name[0]
$members = @()
if ($_.properties.member.Count -eq 0) {
$retrievedAllMembers = $false
$rangeBottom = 0
$rangeTop = 0
while (! $retrievedAllMembers) {
$rangeTop=$rangeBottom+1499
$memberRange="member;range=$rangeBottom-$rangeTop"
$GroupSearcher.PropertiesToLoad.Clear()
[void]$GroupSearcher.PropertiesToLoad.Add("$memberRange")
$rangeBottom+=1500
try {
$result = $GroupSearcher.FindOne()
$rangedProperty = $result.Properties.PropertyNames -like "member;range=*"
$results = $result.Properties.item($rangedProperty)
if ($results.count -eq 0) {
$retrievedAllMembers=$true
} else {
$results | % {
$members += $_
}
}
} catch [System.Management.Automation.MethodInvocationException] {
$retrievedAllMembers=$true
}
}
} else {
$members = $_.properties.member
}
$members | ForEach-Object {
Meatballs1 commented
Sorry cant do a proper PR request from where I am at the moment
Meatballs1 commented
process {
# if a domain is specified, try to grab that domain
if ($Domain){
# try to grab the primary DC for the current domain
try{
$PrimaryDC = ([Array](Get-NetDomainControllers))[0].Name
}
catch{
$PrimaryDC = $Null
}
try {
# reference - http://blogs.msdn.com/b/javaller/archive/2013/07/29/searching-across-active-directory-domains-in-powershell.aspx
$dn = "DC=$($Domain.Replace('.', ',DC='))"
# if we could grab the primary DC for the current domain, use that for the query
if($PrimaryDC){
$GroupSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$PrimaryDC/$dn")
}
else{
# otherwise try to connect to the DC for the target domain
$GroupSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$dn")
}
# samAccountType=805306368 indicates user objects
$GroupSearcher.filter = "(&(objectClass=group)(name=$GroupName))"
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
}
}
else{
$Domain = (Get-NetDomain).Name
# otherwise, use the current domain
$GroupSearcher = [adsisearcher]"(&(objectClass=group)(name=$GroupName))"
}
if ($GroupSearcher){
$GroupSearcher.PageSize = 200
$GroupSearcher.FindAll() | % {
try{
$GroupFoundName = $_.properties.name[0]
$members = @()
if ($_.properties.member.Count -eq 0) {
$retrievedAllMembers = $false
$rangeBottom = 0
$rangeTop = 0
while (! $retrievedAllMembers) {
$rangeTop=$rangeBottom+1499
$memberRange="member;range=$rangeBottom-$rangeTop"
$GroupSearcher.PropertiesToLoad.Clear()
[void]$GroupSearcher.PropertiesToLoad.Add("$memberRange")
$rangeBottom+=1500
try {
$result = $GroupSearcher.FindOne()
$rangedProperty = $result.Properties.PropertyNames -like "member;range=*"
$results = $result.Properties.item($rangedProperty)
if ($results.count -eq 0) {
$retrievedAllMembers=$true
} else {
$results | % {
$members += $_
}
}
} catch [System.Management.Automation.MethodInvocationException] {
$retrievedAllMembers=$true
}
}
} else {
$members = $_.properties.member
}
$members | ForEach-Object {
# for each user/member, do a quick adsi object grab
if ($PrimaryDC){
$properties = ([adsi]"LDAP://$PrimaryDC/$_").Properties
}
else {
$properties = ([adsi]"LDAP://$_").Properties
}
# check if the result is a user account- if not assume it's a group
if ($properties.samAccountType -ne "805306368"){
$isGroup = $True
}
else{
$isGroup = $False
}
$out = New-Object psobject
$out | add-member Noteproperty 'GroupDomain' $Domain
$out | Add-Member Noteproperty 'GroupName' $GroupFoundName
if ($FullData){
$properties.PropertyNames | % {
# TODO: errors on cross-domain users?
if ($_ -eq "objectsid"){
# convert the SID to a string
$out | Add-Member Noteproperty $_ ((New-Object System.Security.Principal.SecurityIdentifier($properties[$_][0],0)).Value)
}
elseif($_ -eq "objectguid"){
# convert the GUID to a string
$out | Add-Member Noteproperty $_ (New-Object Guid (,$properties[$_][0])).Guid
}
else {
if ($properties[$_].count -eq 1) {
$out | Add-Member Noteproperty $_ $properties[$_][0]
}
else {
$out | Add-Member Noteproperty $_ $properties[$_]
}
}
}
}
else {
$MemberDN = $properties.distinguishedName[0]
# extract the FQDN from the Distinguished Name
$MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'
if ($properties.samAccountType -ne "805306368"){
$isGroup = $True
}
else{
$isGroup = $False
}
if ($properties.samAccountName){
# forest users have the samAccountName set
$MemberName = $properties.samAccountName[0]
}
else {
# external trust users have a SID, so convert it
try {
$MemberName = Convert-SidToName $properties.cn[0]
}
catch {
# if there's a problem contacting the domain to resolve the SID
$MemberName = $properties.cn
}
}
$out | add-member Noteproperty 'MemberDomain' $MemberDomain
$out | add-member Noteproperty 'MemberName' $MemberName
$out | add-member Noteproperty 'IsGroup' $IsGroup
$out | add-member Noteproperty 'MemberDN' $MemberDN
$out | add-member Noteproperty 'Mail' $Mail
$out
if($Recurse) {
# if we're recursiving and the returned value isn't a user account, assume it's a group
if($IsGroup){
if($FullData){
Get-NetGroup -Domain $Domain -PrimaryDC $PrimaryDC -FullData -Recurse -GroupName $properties.SamAccountName[0]
}
else {
Get-NetGroup -Domain $Domain -PrimaryDC $PrimaryDC -Recurse -GroupName $properties.SamAccountName[0]
}
}
}
}
}
}
catch {
write-verbose $_
}
}
}
}
}