Windows Vista Forums
Vista Forums Home Join Vista Forums Windows 7 Forum Vista Tutorials Tags
Welcome to Windows Vista Forums. Our forum is dedicated to helping you find solutions with any problems, errors or issues you are experiencing with Windows Vista. The Vista forum also covers news and updates and has an extensive Windows Vista tutorial section that covers a wide range of tips and tricks.

Go Back   Vista Forums > Misc Newsgroups > VB Script

Vista - Return Group Members

Reply
 
Old 07-24-2009   #1 (permalink)
Brian Cahill


 
 

Return Group Members

I have written a script to return all members of a group but it will
only return users. I would like it to return users and nested
groups. Anyone know how this is done? Here is a code snippet:

objGroup1 = InputBox("Enter the first group name:", "Group Name #1")
Set objGroup = GetObject("WinNT://" & objNetwork.UserDomain & "/" &
objGroup1 & ",group")
objGroup.GetInfo

For Each objUser in objGroup.Members
wscript.echo objUser.Name
Next

My System SpecsSystem Spec
Old 07-24-2009   #2 (permalink)
Richard Mueller [MVP]


 
 

Re: Return Group Members

Brian Cahill wrote:
Quote:

>I have written a script to return all members of a group but it will
> only return users. I would like it to return users and nested
> groups. Anyone know how this is done? Here is a code snippet:
>
> objGroup1 = InputBox("Enter the first group name:", "Group Name #1")
> Set objGroup = GetObject("WinNT://" & objNetwork.UserDomain & "/" &
> objGroup1 & ",group")
> objGroup.GetInfo
>
> For Each objUser in objGroup.Members
> wscript.echo objUser.Name
> Next
A recursive subroutine is the most common method. If the .Class property of
the member is "Group", recusively call the subroutine to enmumerate the
members. However, the WinNT provider is blind to global and univerisal
security groups (they were not allowed in NT domains). You need to use the
LDAP provider. With the LDAP provider you need the full Distinguished Name
(DN) of the group. An example could be:
============
strGroup = InputBox("Enter Distinguished Name of group")

Set objGroup = GetObject("LDAP://" & strGroup)

Call EnumMembers(objGroup)

Sub EnumMembers(objGroup)
For Each objMember In objGroup.Members
Wscript.Echo objMember.sAMAccountName
If (LCase(objGroup.Class) = "group") Then
Call EnumMembers(objMember)
End If
Next
End Sub
=========
You could use objGroup.distinguishedName to output the DN of the members
instead of the NT names (sAMAccountName). If you want to have users enter
the NT names of the groups (the NetBIOS or "pre-Windows 2000" names), you
can use the NameTranslate object to convert to the DN required by the LDAP
provider. See this link for details:

http://www.rlmueller.net/NameTranslateFAQ.htm

Also, the example I gave above will get into an infinite loop if there are
circular nested groups. This is unlikely, but can happen. The example below
prevents this by keeping track of the groups in a dictionary object, so the
subroutine recognizes when it has seen a group before:
============
Option Explicit
Dim objRootDSE, strDNSDomain, objTrans, strNetBIOSDomain
Dim strGroup, strGroupDN, objGroup, objGroupList

' Constants for the NameTranslate object.
Const ADS_NAME_INITTYPE_GC = 3
Const ADS_NAME_TYPE_NT4 = 3
Const ADS_NAME_TYPE_1779 = 1

' Determine DNS name of domain from RootDSE.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")

' Use the NameTranslate object to find the NetBIOS domain name from the
' DNS domain name.
Set objTrans = CreateObject("NameTranslate")
objTrans.Init ADS_NAME_INITTYPE_GC, ""
objTrans.Set ADS_NAME_TYPE_1779, strDNSDomain
strNetBIOSDomain = objTrans.Get(ADS_NAME_TYPE_NT4)
' Remove trailing backslash.
strNetBIOSDomain = Left(strNetBIOSDomain, Len(strNetBIOSDomain) - 1)

' Ask for group name (pre-Windows 2000).
strGroup = InputBox("Enter group name")

' Specify the NT format of the name.
objTrans.Set ADS_NAME_TYPE_NT4, strNetBIOSDomain & "\" & strGroup
' Retrieve DN.
strGroupDN = objTrans.Get(ADS_NAME_TYPE_1779)

' Bind to group object.
Set objGroup = GetObject("LDAP://" & strGroupDN)

' Create dictionary object of groups.
Set objGroupList = CreateObject("Scripting.Dictionary")
objGroupList.CompareMode = vbTextCompare

' Enumerate members of the group.
Call EnumMembers(objGroup)

Sub EnumMembers(objGroup)
' Recursive subroutine to enumerate group members.
' Requires that objGroupList be set in the main program
' so it has global scope.
Dim objMember

For Each objMember In objGroup.Members
Wscript.Echo objMember.sAMAccountName
If (LCase(objGroup.Class) = "group") Then
' Check if group seen before.
If (objGroupList.Exists(objGroup.distinguishedName) = False)
Then
' Add this group to the dictionary object.
objGroupList(objGroup.distinguishedName) = True
' Enumerate members of nested group.
Call EnumMembers(objMember)
End If
End If
Next
End Sub
======
I didn't test the above, but you get the idea.

--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--


My System SpecsSystem Spec
Old 07-24-2009   #3 (permalink)
Brian Cahill


 
 

Re: Return Group Members

On Jul 24, 11:01*am, "Richard Mueller [MVP]" <rlmueller-
nos...@xxxxxx> wrote:
Quote:

> Brian Cahill wrote:
Quote:

> >I have written a script to return all members of a group but it will
> > only return users. *I would like it to return users and nested
> > groups. *Anyone know how this is done? *Here is a code snippet:
>
Quote:

> > objGroup1 = InputBox("Enter the first group name:", "Group Name #1")
> > Set objGroup = GetObject("WinNT://" & objNetwork.UserDomain & "/" &
> > objGroup1 & ",group")
> > objGroup.GetInfo
>
Quote:

> > For Each objUser in objGroup.Members
> > wscript.echo objUser.Name
> > Next
>
> A recursive subroutine is the most common method. If the .Class property of
> the member is "Group", recusively call the subroutine to enmumerate the
> members. However, the WinNT provider is blind to global and univerisal
> security groups (they were not allowed in NT domains). You need to use the
> LDAP provider. With the LDAP provider you need the full Distinguished Name
> (DN) of the group. An example could be:
> ============
> strGroup = InputBox("Enter Distinguished Name of group")
>
> Set objGroup = GetObject("LDAP://" & strGroup)
>
> Call EnumMembers(objGroup)
>
> Sub EnumMembers(objGroup)
> * * For Each objMember In objGroup.Members
> * * * * Wscript.Echo objMember.sAMAccountName
> * * * * If (LCase(objGroup.Class) = "group") Then
> * * * * * * Call EnumMembers(objMember)
> * * * * End If
> * * Next
> End Sub
> =========
> You could use objGroup.distinguishedName to output the DN of the members
> instead of the NT names (sAMAccountName). If you want to have users enter
> the NT names of the groups (the NetBIOS or "pre-Windows 2000" names), you
> can use the NameTranslate object to convert to the DN required by the LDAP
> provider. See this link for details:
>
> http://www.rlmueller.net/NameTranslateFAQ.htm
>
> Also, the example I gave above will get into an infinite loop if there are
> circular nested groups. This is unlikely, but can happen. The example below
> prevents this by keeping track of the groups in a dictionary object, so the
> subroutine recognizes when it has seen a group before:
> ============
> Option Explicit
> Dim objRootDSE, strDNSDomain, objTrans, strNetBIOSDomain
> Dim strGroup, strGroupDN, objGroup, objGroupList
>
> ' Constants for the NameTranslate object.
> Const ADS_NAME_INITTYPE_GC = 3
> Const ADS_NAME_TYPE_NT4 = 3
> Const ADS_NAME_TYPE_1779 = 1
>
> ' Determine DNS name of domain from RootDSE.
> Set objRootDSE = GetObject("LDAP://RootDSE")
> strDNSDomain = objRootDSE.Get("defaultNamingContext")
>
> ' Use the NameTranslate object to find the NetBIOS domain name from the
> ' DNS domain name.
> Set objTrans = CreateObject("NameTranslate")
> objTrans.Init ADS_NAME_INITTYPE_GC, ""
> objTrans.Set ADS_NAME_TYPE_1779, strDNSDomain
> strNetBIOSDomain = objTrans.Get(ADS_NAME_TYPE_NT4)
> ' Remove trailing backslash.
> strNetBIOSDomain = Left(strNetBIOSDomain, Len(strNetBIOSDomain) - 1)
>
> ' Ask for group name (pre-Windows 2000).
> strGroup = InputBox("Enter group name")
>
> ' Specify the NT format of the name.
> objTrans.Set ADS_NAME_TYPE_NT4, strNetBIOSDomain & "\" & strGroup
> ' Retrieve DN.
> strGroupDN = objTrans.Get(ADS_NAME_TYPE_1779)
>
> ' Bind to group object.
> Set objGroup = GetObject("LDAP://" & strGroupDN)
>
> ' Create dictionary object of groups.
> Set objGroupList = CreateObject("Scripting.Dictionary")
> objGroupList.CompareMode = vbTextCompare
>
> ' Enumerate members of the group.
> Call EnumMembers(objGroup)
>
> Sub EnumMembers(objGroup)
> * * ' Recursive subroutine to enumerate group members.
> * * ' Requires that objGroupList be set in the main program
> * * ' so it has global scope.
> * * Dim objMember
>
> * * For Each objMember In objGroup.Members
> * * * * Wscript.Echo objMember.sAMAccountName
> * * * * If (LCase(objGroup.Class) = "group") Then
> * * * * * * ' Check if group seen before.
> * * * * * * If (objGroupList.Exists(objGroup.distinguishedName) = False)
> Then
> * * * * * * * * ' Add this group to the dictionary object..
> * * * * * * * * objGroupList(objGroup.distinguishedName) = True
> * * * * * * * * ' Enumerate members of nested group.
> * * * * * * * * Call EnumMembers(objMember)
> * * * * * * End If
> * * * * End If
> * * Next
> End Sub
> ======
> I didn't test the above, but you get the idea.
>
> --
> Richard Mueller
> MVP Directory Services
> Hilltop Lab -http://www.rlmueller.net
> --
Thanks, I ended up using a LDAP SQL query and it works great. Here is
what I ended up with:

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objNetwork = WScript.CreateObject("WScript.Network")
Set objAdRootDSE = GetObject("LDAP://RootDSE")
Set objRS = CreateObject("adodb.recordset")
varConfigNC = objAdRootDSE.Get("defaultNamingContext")
strConnString = "Provider=ADsDSOObject"

' Setup the container that will contain all users in objGroup1 by an
LDAP query
Do
err.number = 0
objGroup1 = InputBox("Enter the first group name:", "Group Name #1")
strSQL = "SELECT * FROM 'LDAP://" & varConfigNC & "' WHERE
objectCategory= 'Group' and SAMAccountName = '" & objGroup1 & "'"
objRS.Open strSQL, strConnstring
Set objGroup = GetObject(objRS.Fields.Item(0))
objRS.Close
If err.number <> 0 Then
errResponse = MsgBox("Please check the group name and try again: " &
err.description, 53, "Error Message")
If errResponse = 2 Then
WScript.quit
End If
End If
Loop Until err.number = 0

For Each objUser in objGroup.Member
wscript.echo (mid(objUser.Name,4))
Next
My System SpecsSystem Spec
Old 07-24-2009   #4 (permalink)
Richard Mueller [MVP]


 
 

Re: Return Group Members


"Brian Cahill" <brianccahill@xxxxxx> wrote in message
news:ef8e171a-09c7-4c1f-85e5-cc35e5ac05da@xxxxxx
Quote:

>Snip...
Thanks, I ended up using a LDAP SQL query and it works great. Here is
what I ended up with:

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objNetwork = WScript.CreateObject("WScript.Network")
Set objAdRootDSE = GetObject("LDAP://RootDSE")
Set objRS = CreateObject("adodb.recordset")
varConfigNC = objAdRootDSE.Get("defaultNamingContext")
strConnString = "Provider=ADsDSOObject"

' Setup the container that will contain all users in objGroup1 by an
LDAP query
Do
err.number = 0
objGroup1 = InputBox("Enter the first group name:", "Group Name #1")
strSQL = "SELECT * FROM 'LDAP://" & varConfigNC & "' WHERE
objectCategory= 'Group' and SAMAccountName = '" & objGroup1 & "'"
objRS.Open strSQL, strConnstring
Set objGroup = GetObject(objRS.Fields.Item(0))
objRS.Close
If err.number <> 0 Then
errResponse = MsgBox("Please check the group name and try again: " &
err.description, 53, "Error Message")
If errResponse = 2 Then
WScript.quit
End If
End If
Loop Until err.number = 0

For Each objUser in objGroup.Member
wscript.echo (mid(objUser.Name,4))
Next

----------
You can use ADO in this way to retrieve DN of the group. Your code assumes
that the DN is the first field in the recordset. I would need to check if
that is true. If your code works, I suppose it is. I would only add that the
NameTranslate object is more efficient, but that doesn't matter much here.
Also, if you want to display the Common Name (without the "cn=" prefix), you
can use:

Wscript.Echo objUser.cn

And, if you want the NT name (your objGroup1 is the NT name of the group,
for example), use:

Wscript.Echo objUser.sAMAccountName

The cn and sAMAccountName attributes often have the same value, but it is
not necessary. The sAMAccountName attribute (pre-Windows 2000 logon name)
uniquely identifies the member (user or group), while cn technically does
not. There can be several objects with the same Common Name, as long as they
are in different OU's.

--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--


My System SpecsSystem Spec
Reply

Thread Tools


Similar Threads
Thread Forum
Get members of a group PowerShell
Remove members of the group. Members are from different domains PowerShell
Members of Group PowerShell
Return of object with synthetic members from functions PowerShell
Identifying group members Vista mail


Vista Forums is an independent web site and has not been authorized,
sponsored, or otherwise approved by Microsoft Corporation.
"Windows Vista", the Start Orb, and related materials are trademarks of Microsoft Corp.
© Designer Media Ltd

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46