Re: Enumerate Empty Global Groups

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Shaun Sawyer (anonymous_at_discussions.microsoft.com)
Date: 04/26/04


Date: Mon, 26 Apr 2004 12:06:01 -0700

Hi Richard,

Many thanks for your efforts (especially if you started this one from scratch!), the script produced the exact results that I needed.

May all questions posted to this newsgroup receive a similar professional responce...

Kind regards,
Shaun
     
     ----- Richard Mueller [MVP] wrote: -----
     
     
     "Richard Mueller [MVP]" <rlmueller-NOSPAM@ameritech.NOSPAM.net> wrote in
     message news:eshm9m6KEHA.4052@TK2MSFTNGP11.phx.gbl...
> Shaun Sawyer wrote:
>>> I am new to this group so please forgive me if the question has been
     asked
> before. We have recently restructure and I want to audit all group
> membership. Is there a simple script for enumerating all Global Groups
> within the domain (regardless of OU) that no longer have any members?
>> Hi,
>> Actually, this is a tricky question. You can use ADO to retrieve all
     groups
> where the member attribute is empty. However, the member attribute does
     not
> include any users that have the group designated as their "primary" group.
> By default, all user objects have the group "Domain Users" designated as
> their "primary group", and all computer objects have "Domain Computers" as
> their "primary" group. These defaults should not be changed. If they have
> not, you can use the script below. For example, the groups "Domain Users"
> and "Domain Computers" may show up as empty, but that may just mean that
     all
> of their members have the group as their "primary" group.
>> Option Explicit
> Dim objRootDSE, strDNSDomain, objCommand, objConnection
> Dim strBase, strFilter, strAttributes, strQuery, objRecordSet
> Dim strNTName
>> ' Determine DNS domain name.
> Set objRootDSE = GetObject("LDAP://RootDSE")
> strDNSDomain = objRootDSE.Get("defaultNamingContext")
>> ' Use ADO to search Active Directory.
> Set objCommand = CreateObject("ADODB.Command")
> Set objConnection = CreateObject("ADODB.Connection")
> objConnection.Provider = "ADsDSOObject"
> objConnection.Open "Active Directory Provider"
> objCommand.ActiveConnection = objConnection
> strBase = "<LDAP://" & strDNSDomain & ">"
>> strFilter = "(&(objectCategory=group)(!(member=*)))"
> strAttributes = "sAMAccountName"
> strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
> objCommand.CommandText = strQuery
> objCommand.Properties("Page Size") = 100
> objCommand.Properties("Timeout") = 30
> objCommand.Properties("Cache Results") = False
> Set objRecordSet = objCommand.Execute
>> Do Until objRecordSet.EOF
> strNTName = objRecordSet.Fields("sAMAccountName")
> Wscript.Echo "Group with no members: " & strNTName
> objRecordSet.MoveNext
> Loop
>> In the filter clause, the "!" means "Not" and "*" is a wildcard. The
     clause
> "(!(member=*))" means where the member attribute is empty (not equal to
> anything). The "member" attribute is a multivalued collection of member
> distinguished names. The "sAMAccountName" attribute is the NT user name,
> also called the "pre-Windows 2000 logon name". The above can be used, if
     you
> remember that any groups listed will not truely be empty if they have
> "primary" group members. I'll have to think how to improve this so it
     lists
> groups that are really empty.
>> --
> Richard
> Microsoft MVP Scripting and ADSI
> HilltopLab web site - http://www.rlmueller.net
> --
     
     
     Hi,
     
     The script below lists all groups in the domain that are empty. I use the
     same procedure as before, using ADO to retrieve all groups where the
     "member" attribute is empty. However, besides the group name I retrieve the
     value of the primaryGroupToken attribute. I put the values into a dynamic
     array. I also construct a filter for another ADO search. This time I look
     for any objects whose "primaryGroupID" attribute matches any of the values
     for "primaryGroupToken" just retrieved. I search for any object of any class
     (user, computer, group, whatever) that has any of the first collection of
     groups designated as their "primary" group. I use a dictionary object to
     keep track of which groups are thereby not truely empty. Finally, I
     enumerate the first collection of groups and only output the names of those
     that are not in the dictionary object. Below is the script:
     
     Option Explicit
     
     Dim objRootDSE, strDNSDomain, objCommand, objConnection
     Dim strBase, strFilter, strAttributes, strQuery, objRecordSet
     Dim strNTName, lngPriGrpToken, arrstrGroups(), k
     Dim objGroupList
     
     Set objGroupList = CreateObject("Scripting.Dictionary")
     
     ' Determine DNS domain name.
     Set objRootDSE = GetObject("LDAP://RootDSE")
     strDNSDomain = objRootDSE.Get("defaultNamingContext")
     
     ' Use ADO to search Active Directory.
     Set objCommand = CreateObject("ADODB.Command")
     Set objConnection = CreateObject("ADODB.Connection")
     objConnection.Provider = "ADsDSOObject"
     objConnection.Open "Active Directory Provider"
     objCommand.ActiveConnection = objConnection
     strBase = "<LDAP://" & strDNSDomain & ">"
     
     strFilter = "(&(objectCategory=group)(!(member=*)))"
     strAttributes = "sAMAccountName,primaryGroupToken"
     strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
     objCommand.CommandText = strQuery
     objCommand.Properties("Page Size") = 100
     objCommand.Properties("Timeout") = 30
     objCommand.Properties("Cache Results") = False
     Set objRecordSet = objCommand.Execute
     
     k = 0
     strFilter = "(|"
     Do Until objRecordSet.EOF
       strNTName = objRecordSet.Fields("sAMAccountName")
       lngPriGrpToken = objRecordSet.Fields("primaryGroupToken")
       ReDim Preserve arrstrGroups(1, k)
       arrstrGroups(0, k) = strNTName
       arrstrGroups(1, k) = lngPriGrpToken
       strFilter = strFilter & "(primaryGroupID=" & lngPriGrpToken & ")"
       k = k + 1
       objRecordSet.MoveNext
     Loop
     
     strFilter = strFilter & ")"
     If strFilter = "(|)" Then
       Wscript.Echo "No empty groups found"
       Wscript.Quit
     End If
     
     strAttributes = "sAMAccountName,primaryGroupID"
     strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
     objCommand.CommandText = strQuery
     Set objRecordSet = objCommand.Execute
     
     Do Until objRecordSet.EOF
       strNTName = objRecordSet.Fields("sAMAccountName")
       lngPriGrpToken = objRecordSet.Fields("primaryGroupID")
       If Not objGroupList.Exists(lngPriGrpToken) Then
         objGroupList(lngPriGrpToken) = True
       End If
       objRecordSet.MoveNext
     Loop
     
     For k = 0 To UBound(arrstrGroups, 2)
       If Not objGroupList.Exists(arrstrGroups(1, k)) Then
         Wscript.Echo "Group with no members: " & arrstrGroups(0, k)
       End If
     Next
     
     --
     Richard
     Microsoft MVP Scripting and ADSI
     HilltopLab web site - http://www.rlmueller.net
     --
     
     
     



Relevant Pages

  • Re: query data from external shell ?
    ... Using VB Script, you would declare an ADO or DAO object, ... Dim objEngine ...
    (microsoft.public.access.conversion)
  • Re: Empty table
    ... > I use ADO .NET and Access. ... When issuing a SELECT statement against an ... > empty table, ... > Dim ds as New Dataset ...
    (microsoft.public.dotnet.languages.vb)
  • Empty table
    ... I use ADO .NET and Access. ... When issuing a SELECT statement against an empty table, ... Dim ds as New Dataset ...
    (microsoft.public.dotnet.languages.vb)
  • Re: ADO interaction with TableDefs.
    ... you have a TableDef object which relates to the tables in a db and you can then test for a .Name property and then if you want run the SQL. ... ADO has no TableDef object that I can find and so how do I cycle through the tables in the db and then run SQL based on the table name? ... Dim cn As ADODB.Connection ... Array(Empty, Empty, Empty, "TABLE")) ...
    (microsoft.public.access.modulesdaovba)
  • RE: export user accounts from NT 4.0 domain
    ... ATTENTION THE SCRIPT MUST BE RUNNED FROM A COMPUTER WHERE EXCEL IS ... from the information in a Microsoft Excel spreadsheet. ... Dim strLast, strFirst, strMiddle, strPW, intRow, intCol ... On Error GoTo 0 ...
    (microsoft.public.windows.server.scripting)