Hey, Scripting Guy!Answering Your OU Questions...for Just 5 Cents
The Microsoft Scripting Guys
Download the code for this article: HeyScriptingGuy2007_03.exe (151KB)
Q How can I display a dialog box that enables me to select an OU from Active Directory?
YOU KNOW, if we Scripting Guys had a nickel for every time we've been asked that question, we'd have -- well, actually, it would only come out to $37.15, wouldn't it? OK, but if we had a nickel for every person who wanted to ask us that question, but just never got around to actually asking, we'd have -- well, the amount doesn't matter. After all, we didn't become Scripting Guys for the money. We became Scripting Guys for the satisfaction that comes from helping people perform their system administration tasks quicker and easier.
Note. OK, so technically we did become Scripting Guys for the money. But then our manager told us, "You know, it is possible for you guys to do well and make a lot of money, but only if you're willing to work really hard and produce nothing but high-quality stuff." That was the moment when we decided money wasn't everything.
No matter. The point is, a lot of people would like to know how to display a dialog box that would enable them to select an OU and then, by extension, connect to that OU using a script. "You've shown us how to display a dialog box that lets us choose folders," says one recent e-mail, "and you've shown us how to display a dialog box that lets us choose files. Why haven't you ever shown us how to display a dialog box that lets us select an OU from Active Directory®?"
Well, to begin with, yes, we really did show people how to display a dialog box that enables them to select a folder and you can find an example of that right here. We also showed everyone how to display a dialog box that allows them to select files; check out microsoft.com/technet/scriptcenter/resources/qanda/jan05/hey0128.mspx if you don't believe us. Both of those articles were well received, and we know that people are employing those techniques in their scripts. So then why haven't we shown people how to display a dialog box that enables them to select OUs from Active Directory? Is this some sort of Microsoft conspiracy or something?
Of course not. (Say, wait a minute: that's exactly what someone involved in a conspiracy would say, isn't it?) The truth is, there's actually a good reason why we haven't shown you how to display a dialog box that enables you to select OUs from Active Directory: no such dialog box exists. As they say in baseball, you can't hit what you can't see. And as we say in scripting, you can't display what doesn't exist.
So, we guess that's it for this month's column. See you next time.
No such luck! According to the editors of TechNet Magazine, that isn't it for this month. "So what if a dialog box like that doesn't exist?" they said. "You're the Scripting Guys, for Pete's sake. Can't you just create a dialog box to take care of this? We thought you guys could do anything when it comes to scripting."
Needless to say, the editors at TechNet Magazine have been grossly misinformed. Do anything when it comes to scripting? Not exactly. The truth is, we Scripting Guys know how to do only one thing when it comes to scripting.
Fortunately, though, that one thing is creating a dialog box that enables you to select an OU from Active Directory. Take a look at Figure 1.
Yes, this is kind of a long script, isn't it? But you know what they say: you can't make an omelet without breaking a few eggs. Likewise, you can't build a custom dialog box without also breaking a few eggs (we got hungry halfway through this column and had to stop for a snack). Now that our appetites are sated, we'll see if we can explain how this all works.
What we're doing with the script is using the Internet Explorer® object model to build a pseudo-dialog box. We're going to create an instance of Internet Explorer, grab a collection of OUs from Active Directory, then display those OUs in a listbox in an Internet Explorer window. We'll wait until the user selects an OU, then grab the ADsPath of the selected item, dismiss the "dialog box," and then go on from there.
Note. Is this going to be the fanciest and prettiest dialog ever created? Yes, if by "fanciest and prettiest" you mean a bare-bones affair that doesn't even have an OK or a Cancel button. But, in our defense, the idea here is to simply give you the basic framework. If you want to pretty up or modify the dialog box, you're on your own.
(Boy, if we had a nickel for every time we said "Sorry, you're on your own," we really would be rich. Send your donations to The Scripting Guys c/o TechNet Magazine.)
In order to fit the explanation of our technique into the space allotted to us, we'll have to skim over a few things. For example, all we'll say about the following block of code is that it creates an instance of Internet Explorer that is 350 pixels by 400 pixels, and, in doing so, hides such things as the address bar and the status bar:
Set objExplorer = CreateObject( _ "InternetExplorer.Application") objExplorer.Navigate "about:blank" objExplorer.ToolBar = 0 objExplorer.StatusBar = 0 objExplorer.Width= 350 objExplorer.Height = 400 objExplorer.Left = 400 objExplorer.Top = 400 objExplorer.Visible = 1
Of course, all this does is give us a blank Internet Explorer window. In order to get the list of OUs in our domain, we need to do a search of Active Directory. We can't explain the ins and outs of Active Directory searching today; for information on that, take a look at our two-part series in the Script Center (microsoft.com/technet/scriptcenter/resources/tales/sg0405.mspx). What we can do is tell you that this is the code we use to retrieve the Name and ADsPath for each OU in the domain fabrikam.com:
objCommand.CommandText = _ "SELECT Name, ADsPath FROM 'LDAP://DC=fabrikam,DC=com' WHERE objectCategory= 'organizationalUnit' ORDER BY Name"
Oh, and just to make things easier for you, we've also sorted the OUs alphabetically by name. That's what the ORDER BY Name clause is for. (No problem; after all, we live to serve.)
When we call the Execute method, we get back a recordset consisting of all the OUs found in fabrikam.com. That means our next step is to display each of those OUs in a listbox.
So how do we do that? Well, first we need to construct the entire listbox in memory. For starters, that means using this line of code to store the <SELECT> tag in a variable named strHTML:
strHTML = "<select size = '20' name='OUList' style='width:300px'>"
What are we doing with this line of code? Well, we're simply constructing a standard HTML listbox (something you do using the <SELECT> tag). Along the way, we give the listbox the Name OUList and configure it to display 20 items at a time and to be 300 pixels (300px) wide. If you know anything about HTML, the previous code should look pretty familiar.
Next, we need to add some items (that is, some OUs) to the listbox. By amazing coincidence, our recordset happens to consist of information about each of the OUs in our domain. Because of that, we can set up a Do Until loop that loops through the entire recordset, grabs the information, then adds each OU to the listbox. Within that loop, we use the following code (again, standard HTML for adding items to a listbox) to add each OU, configuring the item so that the OU Name is displayed in the list and, if you click on that OU in the listbox, the ADsPath is passed to the script:
strHTML = strHTML & "<option value= " & _ Chr(34) & objRecordSet.Fields ("AdsPath").Value & Chr(34) strHTML = strHTML & ">" & objRecordSet. Fields("Name").Value
Why pass the ADsPath to the script? That's easy. Suppose we passed the OU Name instead. If the Name is, say, Finance, it's going to be difficult to bind to that OU; after all, "Finance" by itself isn't a valid ADSI binding string. However, if we get back the ADsPath (LDAP://ou=Finance,dc=fabrikam,dc=com), then binding is a piece of cake. That's because the ADsPath is exactly what we need to locate and connect to an object in Active Directory.
Incidentally, we're displaying the Name in the listbox because we're assuming your OUs have unique names. That might not be the case; for example, the OUs North America\Research and Europe\Research have the same name (Research). If your OUs have duplicate names, you might want to use a different property-say, ADsPath or distinguishedName-in the listbox instead. That's something you'll have to decide for yourself. (Ka-ching! There's another nickel!)
By the way, notice that we're still constructing the listbox in memory: each item added to the box is being added to the variable strHTML. That's all part of the plan: we save the entire code for the listbox to the variable strHTML, then use the value of that variable to actually add the listbox to our instance of Internet Explorer.
After all the OUs have been added, we use this line of code to signify the end of the listbox:
strHTML = strHTML & "</select>"
At this point, strHTML contains all the HTML tagging required to create a listbox, and-best of all-a listbox in which each item represents an OU in Active Directory. That means we can now assign the value of strHTML to the InnerHTML property of our Internet Explorer document:
objExplorer.Document.Body.InnerHTML = strHTML
In turn, that gives us a listbox that displays all the OUs in a domain.
Wait, wait, don't go; we aren't quite finished yet. For example, we still need some code that enables us to pause our script until the user has selected an OU in the dialog box; without it, the listbox would be displayed but the script would continue to run, regardless of whether the user makes a selection. Yikes! To keep that scenario from happening, we use this block of code:
Do While objExplorer.Document.Body.All.OUList.Value = "" Wscript.Sleep 300 Loop
What we're doing here is repeatedly checking the Value of our listbox (which, as you might recall, we named OUList, the same name one of the Scripting Guys gave his daughter). If the Value is an empty string (meaning no item has been selected), we simply pause the script for 300 milliseconds, then loop around, and check again. This continues: a) forever; b) until the user selects an item in the listbox; or c) until the user closes the Internet Explorer window.
Let's assume that the user does select an OU in the listbox. In that case, we take the Value (which, as you recall, is the ADsPath of the OU) and assign it to a variable named strTargetOU:
strTargetOU = objExplorer.Document.Body.All.OUList.Value
We then use the Quit method to dismiss our instance of Internet Explorer as shown below:
At this point, we're almost finished. We first check to see if strTargetOU is equal to an empty string:
If strTargetOU = "" Then Wscript.Quit End If
If it is, that means the user closed Internet Explorer without selecting an OU; in turn, we use the Wscript.Quit method to terminate the script. (We're making the assumption that if the user didn't pick an OU, then he or she isn't really interested in running the script.) If strTargetOU is not equal to an empty string, however, then we echo back the value of the variable:
Of course, in a real script you'd probably go ahead and bind to that OU in Active Directory instead of simply echoing back the ADsPath. But you know what they say -- or at least what we say: for that you're on your own.
As we mentioned, and as you can see in Figure 2, it's not the fanciest dialog box ever created, but it works, and it's way easier than having to type in an ADsPath (assuming you even know the ADsPath). Plus, it gives you the chance to customize the code-and the dialog box-to fit your needs.
Figure 2** A simple script dialog **
Now, if only we had a nickel for every column we've ever written about displaying a dialog box that enables you to select an OU from Active Directory. After all, that would give us 5 cents more than TechNet Magazine usually pays us.
Mind you, we're not complaining.
The Microsoft Scripting Guys work for—well, are employed by—Microsoft. When not playing/coaching/watching baseball (and various other activities) they run the TechNet Script Center. Check it out at www.scriptingguys.com.
© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.