Link to home
Start Free TrialLog in
Avatar of CTCRM
CTCRMFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Copy a list of AD user accounts in a single group into a text editor

How can I copy a list of users name listed in a single AD group into a text editor (notepad)?
ASKER CERTIFIED SOLUTION
Avatar of jppinto
jppinto
Flag of Portugal 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
' EnumGroup.vbs
' VBScript program to document members of a group.
' Reveals nested group and primary group membership.
'
' ----------------------------------------------------------------------
' Copyright (c) 2002-2010 Richard L. Mueller
' Hilltop Lab web site - http://www.rlmueller.net
' Version 1.0 - December 10, 2002
' Version 1.1 - January 24, 2003 - Include users whose Primary Group is
'                                  any nested group.
' Version 1.2 - February 19, 2003 - Standardize Hungarian notation.
' Version 1.3 - March 11, 2003 - Remove SearchScope property.
' Version 1.4 - April 30, 2003 - Use GetInfoEx to retrieve group
'                                primaryGroupToken.
' Version 1.5 - January 25, 2004 - Modify error trapping.
' Version 1.6 - November 6, 2010 - No need to set objects to Nothing.
' Version 1.7 - March 26, 2011 - Output DN instead of sAMAccountName.
'
' You have a royalty-free right to use, modify, reproduce, and
' distribute this script file in any way you find useful, provided that
' you agree that the copyright owner above has no warranty, obligations,
' or liability for such use.

Option Explicit

Dim objGroup, strDN, objMemberList
Dim adoConnection, adoCommand, objRootDSE, strDNSDomain

' Dictionary object to track group membership.
Set objMemberList = CreateObject("Scripting.Dictionary")
objMemberList.CompareMode = vbTextCompare

' Check for required argument.
If (Wscript.Arguments.Count < 1) Then
    Wscript.Echo "Required argument <Distinguished Name> " _
        & "of group missing."
    Wscript.Echo "For example:" & vbCrLf _
        & "cscript //nologo EnumGroup.vbs " _
        & """cn=Test Group,ou=Sales,dc=MyDomain,dc=com"""
    Wscript.Quit(0)
End If

' Bind to the group object with the LDAP provider.
strDN = Wscript.Arguments(0)
On Error Resume Next
Set objGroup = GetObject("LDAP://" & strDN)
If (Err.Number <> 0) Then
    On Error GoTo 0
    Wscript.Echo "Group not found" & vbCrLf & strDN
    Wscript.Quit(1)
End If
On Error GoTo 0

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

' Setup ADO.
Set adoConnection = CreateObject("ADODB.Connection")
Set adoCommand = CreateObject("ADODB.Command")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
Set adoCommand.ActiveConnection = adoConnection
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False

' Enumerate group membership.
Wscript.Echo "Members of group " & objGroup.distinguishedName
Call EnumGroup(objGroup, "  ")

' Clean Up.
adoConnection.Close

Sub EnumGroup(ByVal objADGroup, ByVal strOffset)
    ' Recursive subroutine to enumerate group membership.
    ' objMemberList is a dictionary object with global scope.
    ' objADGroup is a group object bound with the LDAP provider.
    ' This subroutine outputs a list of group members, one member
    ' per line. Nested group members are included. Users are also
    ' included if their primary group is objADGroup. objMemberList
    ' prevents an infinite loop if nested groups are circular.

    Dim strFilter, strAttributes, adoRecordset, intGroupToken
    Dim objMember, strQuery, strDN

    ' Retrieve "primaryGroupToken" of group.
    objADGroup.GetInfoEx Array("primaryGroupToken"), 0
    intGroupToken = objADGroup.Get("primaryGroupToken")

    ' Use ADO to search for users whose "primaryGroupID" matches the
    ' group "primaryGroupToken".
    strFilter = "(primaryGroupID=" & intGroupToken & ")"
    strAttributes = "distinguishedName"
    strQuery = "<LDAP://" & strDNSDomain & ">;" & strFilter & ";" _
        & strAttributes & ";subtree"
    adoCommand.CommandText = strQuery
    Set adoRecordset = adoCommand.Execute
    Do Until adoRecordset.EOF
        strDN = adoRecordset.Fields("distinguishedName").Value
        If (objMemberList.Exists(strDN) = False) Then
            objMemberList.Add strDN, True
            Wscript.Echo strOffset & strDN & " (Primary)"
        Else
            Wscript.Echo strOffset & strDN & " (Primary, Duplicate)"
        End If
        adoRecordset.MoveNext
    Loop
    adoRecordset.Close

    For Each objMember In objADGroup.Members
        If (objMemberList.Exists(objMember.distinguishedName) = False) Then
            objMemberList.Add objMember.distinguishedName, True
            If (UCase(Left(objMember.objectCategory, 8)) = "CN=GROUP") Then
                Wscript.Echo strOffset & objMember.distinguishedName & " (Group)"
                Call EnumGroup(objMember, strOffset & "  ")
            Else
                Wscript.Echo strOffset & objMember.distinguishedName
            End If
        Else
            Wscript.Echo strOffset & objMember.distinguishedName & " (Duplicate)"
        End If
    Next
End Sub

Open in new window

If tere are more than 100 mebers:
' EnumGroup2.vbs
' VBScript program to enumerate members of a group by retrieving the
' "member" multivalued attribute of the group. Uses ADO range limits
' to handle groups with more than 1000 members. Uses a recursive
' subroutine to handle nested groups. Uses a dictionary object to
' recognize duplicate group members (due to nesting).
'
' ----------------------------------------------------------------------
' Copyright (c) 2003 Richard L. Mueller
' Hilltop Lab web site - http://www.rlmueller.net
' Version 1.0 - March 28, 2003
' Version 1.1 - October 29, 2003 - Use dictionary object.
' Version 1.2 - July 31, 2007 - Escape any "/" characters in DN's.
'
' You have a royalty-free right to use, modify, reproduce, and
' distribute this script file in any way you find useful, provided that
' you agree that the copyright owner above has no warranty, obligations,
' or liability for such use.

Option Explicit

Dim strNTName, objRootDSE, strDNSDomain, adoCommand
Dim adoConnection, strBase, strAttributes, objGroupList

' Check for required argument.
If (Wscript.Arguments.Count <> 1) Then
    Wscript.Echo "Required argument <NT Name> missing. " _
        & "For example:" & vbCrLf _
        & "cscript //nologo EnumGroup.vbs ""GroupNTName"""
    Wscript.Quit(0)
End If

strNTName = Wscript.Arguments(0)

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

' Use dictionary object to track unique group members.
Set objGroupList = CreateObject("Scripting.Dictionary")
objGroupList.CompareMode = vbTextCompare

' Use ADO to search Active Directory.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open = "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False

' Specify base of search and "member" attribute to retrieve.
strBase = "<LDAP://" & strDNSDomain & ">"
strAttributes = "member"

' Enumerate group members.
Call EnumMembers(strNTName, "")

Sub EnumMembers(ByVal strName, ByVal strOffset)
    ' Recursive subroutine to enumerate members of a group,
    ' including nested group memberships.
    ' Uses range limits to handle groups with more than 1000 members.

    Dim strFilter, strQuery, adoRecordset, objMember
    Dim strDN, intCount, blnLast, intLowRange
    Dim intHighRange, intRangeStep, objField

    ' Filter on objects of class "group" and specified name.
    strFilter = "(&(ObjectCategory=group)" _
        & "(ObjectClass=group)" _
        & "(sAMAccountName=" & strName & "))"

    ' Setup to retrieve 1000 members at a time.
    blnLast = False
    intRangeStep = 999
    intLowRange = 0
    IntHighRange = intLowRange + intRangeStep

    Do While True

        If (blnLast = True) Then
            ' If last query, retrieve remaining members.
            strQuery = strBase & ";" & strFilter & ";" _
                & strAttributes & ";range=" & intLowRange _
                & "-*;subtree"
        Else
            ' If not last query, retrieve 1000 members.
            strQuery = strBase & ";" & strFilter & ";" _
              & strAttributes & ";range=" & intLowRange & "-" _
              & intHighRange & ";subtree"
        End If
        adoCommand.CommandText = strQuery
        Set adoRecordset = adoCommand.Execute
        intCount = 0

        Do Until adoRecordset.EOF
            For Each objField In adoRecordset.Fields
                If (VarType(objField) = (vbArray + vbVariant)) _
                        Then
                    For Each strDN In objField.Value
                        ' Escape any forward slash characters, "/", with the backslash
                        ' escape character. All other characters that should be escaped are.
                        strDN = Replace(strDN, "/", "\/")
                        ' Check dictionary object for duplicates.
                        If (objGroupList.Exists(strDN) = False) Then
                            ' Add to dictionary object.
                            objGroupList.Add strDN, True

                            ' Bind to each group member, to find "class" of member.
                            Set objMember = GetObject("LDAP://" & strDN)
                            ' Output group member.
                            Wscript.Echo strOffset & "Member of " _
                                & strName & ": " & strDN
                            intCount = intCount + 1
                            If (UCase(objMember.Class) = "GROUP") Then
                                ' If the member is class "group",
                                ' call subroutine recursively.
                                Call _
                                    EnumMembers(objMember.sAMAccountName, _
                                    strOffset & "--")
                            End If
                        Else
                            ' Duplicate member. Output group member.
                            Wscript.Echo strOffset & "Member of " _
                                & strName & ": " & strDN & " (Duplicate)"
                        End If
                    Next
                End If
            Next
            adoRecordset.MoveNext
        Loop
        adoRecordset.Close

        ' If this is the last query, exit the Do While loop.
        If (blnLast = True) Then
            Exit Do
        End If

        ' If the previous query returned no members, then the previous
        ' query for the next 1000 members failed. Perform one more
        ' query to retrieve remaining members (less than 1000).
        If (intCount = 0) Then
            blnLast = True
        Else
            ' Setup to retrieve next 1000 members.
            intLowRange = intHighRange + 1
            intHighRange = intLowRange + intRangeStep
        End If
    Loop
End Sub

Open in new window


save code as EnumGroup2.vbs
to run type

cscript //nologo EnumGroup2.vbs "GroupNTName" > file.txt

Open in new window

Avatar of Krzysztof Pytko
You can use for that Microsoft DS Tools on a DC or any workstation with Administrative Tools installed. Try this syntax

dsquery group -name "GroupName" | dsget group -members -expand | dsget user -fn -ln -samid >>c:\users.txt

If you're interested with DS Tools, I would recommend my blog as startup of using them at
http://kpytko.wordpress.com

Regards,
Krzysztof
or one more way if you wish, is to use Quest PowerShell module for AD. It's completely free and much more flexible in management. First, download it from
http://www.quest.com/powershell/activeroles-server.aspx

and then use thi syntax to do that

Get-QADGroup -name "GroupName" | Get-QADGroupMember -Indirect -SizeLimit 0 | Get-QADUser | Select sAMAccountName,givenName,sn | Export-CSV c:\group-members.csv

Krzysztof
Avatar of CTCRM

ASKER

ippinto - The script has extracted a complete list of AD accounts which is good but how can I extract a list of users in a single AD Group?
Avatar of CTCRM

ASKER

Very good advice, I just needed to granulate the extraction a little more.