Solved

VBScript to list number of member in Active Directory

Posted on 2012-03-28
16
776 Views
Last Modified: 2012-03-29
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?
0
Comment
Question by:netjon
  • 9
  • 7
16 Comments
 
LVL 67

Expert Comment

by:sirbounty
ID: 37778951
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

0
 

Author Comment

by:netjon
ID: 37781992
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.
0
 
LVL 67

Expert Comment

by:sirbounty
ID: 37782101
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

0
 

Author Comment

by:netjon
ID: 37782134
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.
0
 

Author Comment

by:netjon
ID: 37782159
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.
0
 
LVL 67

Expert Comment

by:sirbounty
ID: 37782215
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...
0
 

Author Comment

by:netjon
ID: 37782239
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.
0
 

Author Comment

by:netjon
ID: 37782266
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?
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 

Author Comment

by:netjon
ID: 37782352
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

0
 
LVL 67

Expert Comment

by:sirbounty
ID: 37782458
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

0
 

Author Comment

by:netjon
ID: 37782496
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?
0
 
LVL 67

Accepted Solution

by:
sirbounty earned 500 total points
ID: 37782654
Yeah, testing somewhat here, but haven't really found a similar situation in what I'm scanning.

The issue may be the group class, so give this a shot and let me know what you find....

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
  i = 0
  Set objTypes = CreateObject("Scripting.Dictionary")
  Set objUsers = CreateObject("Scripting.Dictionary")

  Set objGrp= GetObject(objRecordSet.Fields("ADsPath").Value)

  For Each strUser in objGrp.Member
    i = i + 1
    Set objMember = GetObject("LDAP://" & strUser)
    strType = objMember.Class

    If Not objTypes.Exists(strType) Then 
      objTypes.Add strType, "1"
    Else
      objTypes.Item(strType) = objTypes.Item(strType) + 1
    End If
    
    objUsers.Add strUser, i
    
  Next
  
  If i < 3 then
    objFile.WriteLine objGrp.CN & " contains: "
    For Each oUser in objUsers
      objFile.WriteLine oUser 
    Next
    For Each oType in objTypes 
      If Trim(oType) <> "" Then objFile.WriteLine vbTab & oType & " count: " & objTypes.Item(oType)
'    objFile.WriteLine objGrp.CN & Space(40-Len(objGrp.CN)) & i
    Next
    objFile.WriteLine
  End If

  objRecordSet.MoveNext
Loop   

objFile.Close

Open in new window

0
 

Author Comment

by:netjon
ID: 37782675
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.
0
 
LVL 67

Expert Comment

by:sirbounty
ID: 37782766
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!
0
 

Author Comment

by:netjon
ID: 37782808
I wonder if it's because you had
i=0

Open in new window

instead of
Set i=0

Open in new window

?
0
 
LVL 67

Expert Comment

by:sirbounty
ID: 37782996
No, that's not it.  you use set to instantiate an object.  i is an integer variable.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

How can you create a game plan that lets you focus on special projects instead of running from cubicle to cubicle every day and feeling like you’ve accomplished nothing? Try these strategies for prioritizing your tasks, offloading what you can, and …
Our Group Policy work started with Small Business Server in 2000. Microsoft gave us an excellent OU and GPO model in subsequent SBS editions that utilized WMI filters, OU linking, and VBS scripts. These are some of experiences plus our spending a lo…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now