none
PowerShell: AD Group Membership

    Question

  • Is it possible to generate group membership for all groups in AD, b member of that group?

     

    Thanks


    *alex
    Wednesday, June 01, 2011 6:47 PM

Answers

  • One good thing about using DirectoryServices.DirectorySearcher in PowerShell is that the syntax is so similar to similar VBScript programs using ADODB. The first program in VBScript would be as follows:

     

    Option Explicit

    Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
    Dim objRootDSE, strDNSDomain, strQuery, adoRecordset, strName, strDN
    Dim strLine, arrMembers, strMember

    ' Setup ADO objects.
    Set adoCommand = CreateObject("ADODB.Command")
    Set adoConnection = CreateObject("ADODB.Connection")
    adoConnection.Provider = "ADsDSOObject"
    adoConnection.Open "Active Directory Provider"
    Set adoCommand.ActiveConnection = adoConnection

    ' Search entire Active Directory domain.
    Set objRootDSE = GetObject("LDAP://RootDSE")
    strDNSDomain = objRootDSE.Get("defaultNamingContext")
    strBase = "<LDAP://" & strDNSDomain & ">"

    ' Filter on group objects.
    strFilter = "(objectCategory=group)"

    ' Comma delimited list of attribute values to retrieve.
    strAttributes = "distinguishedName,sAMAccountName,member"

    ' Construct the LDAP syntax query.
    strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
    adoCommand.CommandText = strQuery
    adoCommand.Properties("Page Size") = 200
    adoCommand.Properties("Timeout") = 30
    adoCommand.Properties("Cache Results") = False

    ' Run the query.
    Set adoRecordset = adoCommand.Execute

    ' Enumerate the resulting recordset.
    Do Until adoRecordset.EOF
        ' Retrieve values and display.
        strDN = adoRecordset.Fields("distinguishedName").Value
        strName = adoRecordset.Fields("sAMAccountName").Value
        strLine = """" & strDN & """,""" & strName & """"
        arrMembers = adoRecordset.Fields("member").Value
        If Not IsNull(arrMembers) Then
            For Each strMember In arrMembers
                strLine = strLine & ",""" & strMember & """"
            Next
        End If
        Wscript.Echo strLine
        ' Move to the next record in the recordset.
        adoRecordset.MoveNext
    Loop

    ' Clean up.
    adoRecordset.Close
    adoConnection.Close

     

    The second program, where sAMAccountName's are substituted for member DN's, would be as follows:

     

    Option Explicit

    Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
    Dim objRootDSE, strDNSDomain, strQuery, adoRecordset, strName, strDN
    Dim strLine, arrMembers, strMember, objMemberList

    ' Setup ADO objects.
    Set adoCommand = CreateObject("ADODB.Command")
    Set adoConnection = CreateObject("ADODB.Connection")
    adoConnection.Provider = "ADsDSOObject"
    adoConnection.Open "Active Directory Provider"
    Set adoCommand.ActiveConnection = adoConnection

    ' Search entire Active Directory domain.
    Set objRootDSE = GetObject("LDAP://RootDSE")
    strDNSDomain = objRootDSE.Get("defaultNamingContext")
    strBase = "<LDAP://" & strDNSDomain & ">"

    ' Retrieve all users, groups, and computers.
    strFilter = "(|(objectCategory=user)(objectCategory=group)(objectCategory=computer))"

    ' Comma delimited list of attribute values to retrieve.
    strAttributes = "distinguishedName,sAMAccountName"

    ' Dictionary object (hash table).
    Set objMemberList = CreateObject("Scripting.Dictionary")
    objMemberList.CompareMode = vbTextCompare

    ' Construct the LDAP syntax query.
    strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
    adoCommand.CommandText = strQuery
    adoCommand.Properties("Page Size") = 200
    adoCommand.Properties("Timeout") = 30
    adoCommand.Properties("Cache Results") = False

    ' Run the query.
    Set adoRecordset = adoCommand.Execute

    ' Enumerate the recordset.
    Do Until adoRecordset.EOF
        ' Retrieve values and display.
        strDN = adoRecordset.Fields("distinguishedName").Value
        strName = adoRecordset.Fields("sAMAccountName").Value
        ' Skip contacts.
        If (strName <> "") Then
            objMemberList.Add strDN, strName
        End If
        ' Move to the next record in the recordset.
        adoRecordset.MoveNext
    Loop
    ' Recordset must be closed before it can be opened again.
    adoRecordset.Close

    ' Filter on all group objects.
    strFilter = "(objectCategory=group)"

    ' Comma delimited list of attribute values to retrieve.
    strAttributes = "distinguishedName,sAMAccountName,member"

    ' Construct the LDAP syntax query.
    strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
    adoCommand.CommandText = strQuery

    ' Run the query.
    Set adoRecordset = adoCommand.Execute

    ' Enumerate the resulting recordset.
    Do Until adoRecordset.EOF
        ' Retrieve values and display.
        strDN = adoRecordset.Fields("distinguishedName").Value
        strName = adoRecordset.Fields("sAMAccountName").Value
        strLine = """" & strDN & """,""" & strName & """"
        arrMembers = adoRecordset.Fields("member").Value
        If Not IsNull(arrMembers) Then
            For Each strMember In arrMembers
                If (objMemberList.Exists(strMember) = True) Then
                    ' Substitute the sAMAccountname from dictionary object.
                    strLine = strLine & ",""" & objMemberList(strMember) & """"
                Else
                    ' Use the Distinguished Name.
                    strLine = strLine & ",""" & strMember & """"
                End If
            Next
        End If
        Wscript.Echo strLine
        ' Move to the next record in the recordset.
        adoRecordset.MoveNext
    Loop

    ' Clean up.
    adoRecordset.Close
    adoConnection.Close

     

     


    Richard Mueller - MVP Directory Services
    Sunday, June 05, 2011 10:01 PM
    Moderator

All replies

  • A PowerShell V1 script to retrieve all groups in the domain, and their direct membership, and output in comma delimited format, could be:

     

    $D = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
    $Domain = [ADSI]"LDAP://$D"
    $Searcher = New-Object System.DirectoryServices.DirectorySearcher
    $Searcher.PageSize = 200
    $Searcher.SearchScope = "subtree"

    # Filter on all groups.
    $Searcher.Filter = "(objectCategory=group)"
    $Searcher.PropertiesToLoad.Add("distinguishedName") > $Null
    $Searcher.PropertiesToLoad.Add("sAMAccountName") > $Null
    $Searcher.PropertiesToLoad.Add("member") > $Null
    $Searcher.SearchRoot = "LDAP://" + $Domain.distinguishedName

    $Results = $Searcher.FindAll()
    ForEach ($Result In $Results)
    {
        $DN = $Result.Properties.Item("distinguishedName")
        $Name = $Result.Properties.Item("sAMAccountName")
        $Line = """DN,$Name"""
        $Members = $Result.Properties.Item("member")
        ForEach ($Member In $Members)
        {
            $Line = $Line + ",""" + $Member + """"
        }
        $Line
    }

     

    This outputs Distinguished Names. To output sAMAccountNames, you would either need to bind to all member objects (not very efficient), or first retrieve all user, group, and computer sAMAccountNames and save in a hash table. Then query again for all groups, and use the hash table to substitute sAMAccountNames for the members. For example:

     

    $D = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
    $Domain = [ADSI]"LDAP://$D"
    $Searcher = New-Object System.DirectoryServices.DirectorySearcher
    $Searcher.PageSize = 200
    $Searcher.SearchScope = "subtree"
    $Searcher.SearchRoot = "LDAP://" + $Domain.distinguishedName

    # Specify attributes to retrieve.
    $Searcher.PropertiesToLoad.Add("distinguishedName") > $Null
    $Searcher.PropertiesToLoad.Add("sAMAccountName") > $Null

    # Hash table.
    $MemberList = @{}

    # Retrieve all users, groups, and computers.
    $Searcher.Filter = "(|(objectCategory=user)(objectCategory=group)(objectCategory=computer))"
    $Results = $Searcher.FindAll()
    ForEach ($Result In $Results)
    {
        $DN = $Result.Properties.Item("distinguishedName")
        $Name = $Result.Properties.Item("sAMAccountName")
        $MemberList.Add($($DN), $($Name))
    }

    # Filter on all groups.
    $Searcher.Filter = "(objectCategory=group)"
    $Searcher.PropertiesToLoad.Add("member") > $Null

    $Results = $Searcher.FindAll()
    ForEach ($Result In $Results)
    {
        $Name = $Result.Properties.Item("sAMAccountName")
        $Line = """DN,$Name"""
        $Members = $Result.Properties.Item("member")
        ForEach ($Member In $Members)
        {
            If ($MemberList.ContainsKey($Member))
            {
                # Substitute the sAMAccountName from hash table.
                $Line = $Line + ",""" + $MemberList[$Member] + """"
            }
            Else
            {
                # Use the Distinguished Name.
                $Line = $Line + ",""" + $Member + """"
            }
        }
        $Line
    }

     

    You could also do this with the AD cmdlets in PowerShell V2.

     


    Richard Mueller - MVP Directory Services
    • Edited by Richard MuellerMVP, Moderator Sunday, June 05, 2011 9:24 PM Typo in both programs. Should be $Members = $Result.Properties.Item("member")
    Wednesday, June 01, 2011 8:07 PM
    Moderator
  • Richard,

     

    I'll need to go the vbscript route on this. Any thoughts there?


    *alex
    Thursday, June 02, 2011 5:24 PM
  • Actually, I found this on Richard's site:

    http://www.rlmueller.net/List%20Members%20of%20a%20Group.htm

    With a little modification on one of these, that should be able to do what you want.


    Paul Frankovich
    Thursday, June 02, 2011 5:38 PM
  • One good thing about using DirectoryServices.DirectorySearcher in PowerShell is that the syntax is so similar to similar VBScript programs using ADODB. The first program in VBScript would be as follows:

     

    Option Explicit

    Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
    Dim objRootDSE, strDNSDomain, strQuery, adoRecordset, strName, strDN
    Dim strLine, arrMembers, strMember

    ' Setup ADO objects.
    Set adoCommand = CreateObject("ADODB.Command")
    Set adoConnection = CreateObject("ADODB.Connection")
    adoConnection.Provider = "ADsDSOObject"
    adoConnection.Open "Active Directory Provider"
    Set adoCommand.ActiveConnection = adoConnection

    ' Search entire Active Directory domain.
    Set objRootDSE = GetObject("LDAP://RootDSE")
    strDNSDomain = objRootDSE.Get("defaultNamingContext")
    strBase = "<LDAP://" & strDNSDomain & ">"

    ' Filter on group objects.
    strFilter = "(objectCategory=group)"

    ' Comma delimited list of attribute values to retrieve.
    strAttributes = "distinguishedName,sAMAccountName,member"

    ' Construct the LDAP syntax query.
    strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
    adoCommand.CommandText = strQuery
    adoCommand.Properties("Page Size") = 200
    adoCommand.Properties("Timeout") = 30
    adoCommand.Properties("Cache Results") = False

    ' Run the query.
    Set adoRecordset = adoCommand.Execute

    ' Enumerate the resulting recordset.
    Do Until adoRecordset.EOF
        ' Retrieve values and display.
        strDN = adoRecordset.Fields("distinguishedName").Value
        strName = adoRecordset.Fields("sAMAccountName").Value
        strLine = """" & strDN & """,""" & strName & """"
        arrMembers = adoRecordset.Fields("member").Value
        If Not IsNull(arrMembers) Then
            For Each strMember In arrMembers
                strLine = strLine & ",""" & strMember & """"
            Next
        End If
        Wscript.Echo strLine
        ' Move to the next record in the recordset.
        adoRecordset.MoveNext
    Loop

    ' Clean up.
    adoRecordset.Close
    adoConnection.Close

     

    The second program, where sAMAccountName's are substituted for member DN's, would be as follows:

     

    Option Explicit

    Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
    Dim objRootDSE, strDNSDomain, strQuery, adoRecordset, strName, strDN
    Dim strLine, arrMembers, strMember, objMemberList

    ' Setup ADO objects.
    Set adoCommand = CreateObject("ADODB.Command")
    Set adoConnection = CreateObject("ADODB.Connection")
    adoConnection.Provider = "ADsDSOObject"
    adoConnection.Open "Active Directory Provider"
    Set adoCommand.ActiveConnection = adoConnection

    ' Search entire Active Directory domain.
    Set objRootDSE = GetObject("LDAP://RootDSE")
    strDNSDomain = objRootDSE.Get("defaultNamingContext")
    strBase = "<LDAP://" & strDNSDomain & ">"

    ' Retrieve all users, groups, and computers.
    strFilter = "(|(objectCategory=user)(objectCategory=group)(objectCategory=computer))"

    ' Comma delimited list of attribute values to retrieve.
    strAttributes = "distinguishedName,sAMAccountName"

    ' Dictionary object (hash table).
    Set objMemberList = CreateObject("Scripting.Dictionary")
    objMemberList.CompareMode = vbTextCompare

    ' Construct the LDAP syntax query.
    strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
    adoCommand.CommandText = strQuery
    adoCommand.Properties("Page Size") = 200
    adoCommand.Properties("Timeout") = 30
    adoCommand.Properties("Cache Results") = False

    ' Run the query.
    Set adoRecordset = adoCommand.Execute

    ' Enumerate the recordset.
    Do Until adoRecordset.EOF
        ' Retrieve values and display.
        strDN = adoRecordset.Fields("distinguishedName").Value
        strName = adoRecordset.Fields("sAMAccountName").Value
        ' Skip contacts.
        If (strName <> "") Then
            objMemberList.Add strDN, strName
        End If
        ' Move to the next record in the recordset.
        adoRecordset.MoveNext
    Loop
    ' Recordset must be closed before it can be opened again.
    adoRecordset.Close

    ' Filter on all group objects.
    strFilter = "(objectCategory=group)"

    ' Comma delimited list of attribute values to retrieve.
    strAttributes = "distinguishedName,sAMAccountName,member"

    ' Construct the LDAP syntax query.
    strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
    adoCommand.CommandText = strQuery

    ' Run the query.
    Set adoRecordset = adoCommand.Execute

    ' Enumerate the resulting recordset.
    Do Until adoRecordset.EOF
        ' Retrieve values and display.
        strDN = adoRecordset.Fields("distinguishedName").Value
        strName = adoRecordset.Fields("sAMAccountName").Value
        strLine = """" & strDN & """,""" & strName & """"
        arrMembers = adoRecordset.Fields("member").Value
        If Not IsNull(arrMembers) Then
            For Each strMember In arrMembers
                If (objMemberList.Exists(strMember) = True) Then
                    ' Substitute the sAMAccountname from dictionary object.
                    strLine = strLine & ",""" & objMemberList(strMember) & """"
                Else
                    ' Use the Distinguished Name.
                    strLine = strLine & ",""" & strMember & """"
                End If
            Next
        End If
        Wscript.Echo strLine
        ' Move to the next record in the recordset.
        adoRecordset.MoveNext
    Loop

    ' Clean up.
    adoRecordset.Close
    adoConnection.Close

     

     


    Richard Mueller - MVP Directory Services
    Sunday, June 05, 2011 10:01 PM
    Moderator