Recipe 15.24. Script: Displaying the Structure of a ForestDo you know the structure of your Active Directory forest? You could use a tool such as ADSI Edit and expand all of the OUs and containers in each domain, but if you have a lot of OUs, this would be very time consuming. With a pretty simple script, you can enumerate all the domains, OUs, and containers in a forest. And you don't need any type of privileged rights to do it. Here is the script: ' This code prints out the forest tree hierarchy ' BEGIN SECTION 1 set objRootDSE = GetObject("LDAP://RootDSE") strBase = "<LDAP://cn=Partitions," & _ objRootDSE.Get("ConfigurationNamingContext") & ">;" strFilter = "(&(objectcategory=crossRef)(systemFlags=3));" strAttrs = "name,trustParent,nCName,dnsRoot,distinguishedName;" strScope = "onelevel" set objConn = CreateObject("ADODB.Connection") objConn.Provider = "ADsDSOObject" objConn.Open "Active Directory Provider" set objRS = objConn.Execute(strBase & strFilter & strAttrs & strScope) objRS.MoveFirst ' END SECTION 1 ' BEGIN SECTION 2 set dicSubDomainTrue = CreateObject("Scripting.Dictionary") set dicDomainHierarchy = CreateObject("Scripting.Dictionary") set dicDomainRoot = CreateObject("Scripting.Dictionary") ' END SECTION 2 ' BEGIN SECTION 3 while not objRS.EOF dicDomainRoot.Add objRS.Fields("name").Value, objRS.Fields("nCName").Value if objRS.Fields("trustParent").Value <> "" then dicSubDomainTrue.Add objRS.Fields("name").Value, 0 set objDomainParent = GetObject("LDAP://" & _ objRS.Fields("trustParent").Value) dicDomainHierarchy.Add objRS.Fields("name").Value, _ objDomainParent.Get("name") else dicSubDomainTrue.Add objRS.Fields("name").Value, 1 end if objRS.MoveNext wend ' END SECTION 3 ' BEGIN SECTION 4 for each strDomain in dicSubDomainTrue if dicSubDomainTrue(strDomain) = 1 then DisplayDomains strDomain, "", dicDomainHierarchy, dicDomainRoot end if next Function DisplayDomains ( strDomain, strSpaces, dicDomainHierachy, dicDomainRoot) WScript.Echo strSpaces & strDomain DisplayObjects "LDAP://" & dicDomainRoot(strDomain), " " & strSpaces for each strD in dicDomainHierarchy if dicDomainHierarchy(strD) = strDomain then DisplayDomains strD, " " & strSpaces, dicDomainHierarchy, _ dicDomainRoot end if next End Function ' DisplayObjects takes the ADsPath of the object to display ' child objects for and the number of spaces (indention) to ' use when printing the first parameter Function DisplayObjects( strADsPath, strSpace) set objObject = GetObject(strADsPath) Wscript.Echo strSpace & objObject.Name objObject.Filter = Array("container","organizationalUnit") for each objChildObject in objObject DisplayObjects objChildObject.ADsPath, strSpace & " " next End Function ' END SECTION 4 This script is a little more complicated than most of the scripts in this book, but you should be able to handle it. Let's walk through it. In SECTION 1, I set up an ADO query to find all domains in a forest. This is a little trickier than you might imagine. Domains are represented in the Configuration naming context as crossRef objects; but since LDAP referrals can also be created as crossRef objects, I have to look for a specific type of crossRef object, ones that have a systemFlags attribute equal to 3. This signifies Active Directory domains. In SECTION 2, I set up three dictionary objects that I'll use throughout the script. Here is a brief overview of each dictionary object:
In SECTION 3, I enumerate over each of the values returned by the ADO query started in SECTION 1. I first set the domain root in the dicDomainRoot dictionary. Next, I evaluate if the trustParent attribute contains a value. If it does, then I know the domain I'm currently on has a parent domain. If TRustParent does not contain a value, I know that it is the root domain of the forest or domain tree. If it does have a parent, I set an entry for the domain in dicSubDomainTrue to 0 to signify that I haven't found a subdomain for this domain yet. I then set an entry in dicDomainHierarchy to contain the domain and parent domain as key value pairs. At this point, I've set up all the data structures I need to start printing out the structure of a forest. In SECTION 4, I start iterating over each domain in the forest. I'll enter only the domains that are roots of their forests. Then I call the DisplayDomains function. DisplayDomains prints the name of the current domain and calls DisplayObjects to print each container and organizationalUnit object in the domain. This effectively prints the structure of that domain. After it is done with that, it starts to loop over the keys in dicDomainHierarchy to find all child domains that have the current domain set as their parent. If it finds a subdomain of the current domain, it calls DisplayDomains (recursively) on that domain and the process repeats. |