Link to home
Start Free TrialLog in
Avatar of netjon
netjon

asked on

VBScript to list number of member in Active Directory

We have about 200 groups in our Active Directory that we want to start doing some cleanup on.  First we just want to find any groups with just 2 or less members.  So far I have this script that will list the members of a group:

On Error Resume Next
 
Set objGroup = GetObject ("LDAP://cn=Accounting,ou=Groups,ou=Exchange Users,dc=OurDomain,dc=com")
objGroup.GetInfo

arrMemberOf = objGroup.GetEx("member")

WScript.Echo "Members:"
For Each strMember in arrMemberOf
  WScript.echo strMember
Next

Open in new window


But note that I had to specify the CN ("Accounting").  Lacking VBScript skill, is there an easy way to cycle through all groups under the "Groups" OU and spit out the list of members if that list is 2 or less members?
Avatar of sirbounty
sirbounty
Flag of United States of America image

Try this: (modify yourDC and yourDomain below)

on error resume next

Const ADS_SCOPE_SUBTREE = 2

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

objCommand.CommandText = _
    "SELECT ADsPath FROM 'LDAP://dc=YOURDC,dc=YOURDOMAIN,dc=com' WHERE objectCategory='group' "
    
Set objRecordSet = objCommand.Execute

objRecordSet.MoveFirst
Do Until objRecordSet.EOF
    Set objGrp= GetObject(objRecordSet.Fields("ADsPath").Value)

    If objGrp.GroupType < 0 THen 
      objGrp.GetInfo
      arrMembers = objGrp.GetEx("member")

      If uBound(arrMembers) - 1 < 3 Then
        wscript.echo objGrp.CN & " has less than 3 members..."
      end if
    end if
    objRecordSet.MoveNext
Loop

Open in new window

Avatar of netjon
netjon

ASKER

I had to tweak it a bit, but with your logic processing, it leaves me with an issue at the end when I want to output the number of members in each group.  Here is what your code has evolved into:

on error resume next

Const ADS_SCOPE_SUBTREE = 2

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("output.txt", True)

objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

objCommand.CommandText = "SELECT ADsPath FROM 'LDAP://ou=groups,ou=Exchange Users,dc=MyDomain,dc=com' WHERE objectCategory='group' "
    
Set objRecordSet = objCommand.Execute

objFile.WriteLine "The following have less than 3 members:"
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
    Set objGrp= GetObject(objRecordSet.Fields("ADsPath").Value)

    If objGrp.GroupType < 0 Then 
      objGrp.GetInfo
      arrMembers = objGrp.GetEx("member")

      If uBound(arrMembers) < 2 Then
        objFile.WriteLine objGrp.CN & Space(40-Len(objGrp.CN)) & uBound(arrMembers)+1
      end if
    end if
    objRecordSet.MoveNext
Loop  

Open in new window


The problem is using uBound(arrMembers) . . . If a group has 1 member, then this will be 0.  But if a group has 0 members, it seems to also be 0.  So my final product gives me a list of groups and their members, except that a "1" [uBound(arrMembers)+1] could mean the group has 0 members OR 1 member.  I know there are groups with 0 members, but can't tell that from the output.

Could there be a way to do an If statement like ...

If uBound(arrMembers) = 0 Then
    If arrMembers.ContainsNothing Then objFile.WriteLine "0"
    Else objFile.WriteLine "1"
    End If
End If

Open in new window


That was obviously pseduo-code.  Not sure if it's possible with VBScript.
Ok, slightly different scope, but if that's what you want, then this should take care of it for you:

on error resume next

Const ADS_SCOPE_SUBTREE = 2

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("output.txt", True)

objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

objCommand.CommandText = "SELECT ADsPath FROM 'LDAP://ou=groups,ou=Exchange Users,dc=MyDomain,dc=com' WHERE objectCategory='group' "
    
Set objRecordSet = objCommand.Execute

objFile.WriteLine "The following have less than 3 members:"
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
    Set objGrp= GetObject(objRecordSet.Fields("ADsPath").Value)

    If objGrp.GroupType < 0 Then 
      i = 0
     For Each strUser in objGrp.Member
        i = i + 1
      Next
      If i < 3 then objFile.WriteLine objGrp.CN & Space(40-Len(objGrp.CN)) & i
   end if
   objRecordSet.MoveNext
Loop  

Open in new window

Avatar of netjon

ASKER

That still gives me the same number count for each group, meaning all is well except that groups with 0 are showing up as having 1 member.
Avatar of netjon

ASKER

You know what the problem could be . . . I added the output of arrMembers in addition to the count, and one group I know has 0 member that shows up having 1 member shows that the member is a user called Jerry.  Coincidentally, the previously listed group only had Jerry in it.  So maybe we should be cleaning out arrMember on each loop iteration?  Looks like on 0 members it gets stuck with previous garbage.
The latest code above doesn't use arrMember any longer.  And i gets reset to 0 on each record, so that shouldn't pose a problem...
Avatar of netjon

ASKER

Weird.  Well I'm definitely only getting 1's and 2's on my output.  The 2's are correct, but 1's are being listed for groups with 0 members and groups with 1 member.
Avatar of netjon

ASKER

What's the best way, given the most recent code revision you've given, to output the names of the members as well as the count?
Avatar of netjon

ASKER

What is the purpose of:

If objGrp.GroupType < 0 Then i = 0

Open in new window


Why not just
i = 0

Open in new window

You can remove that line - it limits the groups to security groups.
This should display the members.  Let me know how you make out.

on error resume next

Const ADS_SCOPE_SUBTREE = 2

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("output.txt", True)

objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

objCommand.CommandText = "SELECT ADsPath FROM 'LDAP://ou=groups,ou=Exchange Users,dc=MyDomain,dc=com' WHERE objectCategory='group' "
    
Set objRecordSet = objCommand.Execute

objFile.WriteLine "The following have less than 3 members:"
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
    Set objGrp= GetObject(objRecordSet.Fields("ADsPath").Value)

      i = 0
     For Each strUser in objGrp.Member
        i = i + 1
      Next
      If i < 3 then
        For Each strUser in objGrp.Member
          wcsript.echo strUser
        Next
        objFile.WriteLine objGrp.CN & Space(40-Len(objGrp.CN)) & i
    end if
   end if
   objRecordSet.MoveNext
Loop  

Open in new window

Avatar of netjon

ASKER

Ok, in doing so my output looks like this:

Group_I_Know_Has_0_Members     -     1 member
        Members:
Group_I_Know_Has_1_Member       -     1 member
        Members:
Group_I_Know_Has_2_Members      -     2 members
        Members: Jerry, John
Group_I_Know_Has_2_Members      -     2 members
        Members: Jerry, Accounting
Group_I_Know_Has_1Member        -      1 member
        Members:
[...]


So groups with 0 and 1 members not only show as having one member in variable "i" but also have no "strUsers" in objGroup.Member.

What do you make of that?  Do you have a domain environment you could test this with?
ASKER CERTIFIED SOLUTION
Avatar of sirbounty
sirbounty
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of netjon

ASKER

Eh, I've figured out a workaround that at least works.

I do an If statement to test if ( i = 1 ) and then a nested If statement to test if ( objGrp.Member = "" ) which would signify a 0-member group.  I then adjust the output to just say "0."  Also, to list users for groups of 1-member, I need to output objGrp.Member directly -- Cycling through that array with strUser works with groups of more than one member, but for some reason outputs nothing for single-member groups.

It's a bit confusing, but it works for me, and I haven't tried this latest solution you've posted because you posted midway through me writing this.  You get all the points, of course, because I couldn't have done this without you.
Glad you got it working.
The above will display the count of group members who are users, vs other groups, vs contacts, etc...

Thanks for the grade!
Avatar of netjon

ASKER

I wonder if it's because you had
i=0

Open in new window

instead of
Set i=0

Open in new window

?
No, that's not it.  you use set to instantiate an object.  i is an integer variable.