Active Directory TreeView / Select AD Container Dialog
This is a WinForms dialog window (I have a WPF version as well, if anyone wants that just let me know) that will show all containers and OUs in a specified domain and let the user select a container/OU. You can then retrieve the full distinguished name for the OU they selected by checking the SelectedContainerPath property after you have shown the dialog window.
UPDATED 10/11/2011
I've removed the old version of this control and replaced it with a new version which is actually a proper dialog window rather than a control and is a lot faster, better written, no longer requires you to provide the OU/container icons yourself, and is used more similarly to other standard .NET dialog windows
Here's a screenshot of the new version in action
There's an example project that shows how to use the dialog window within the attached solution, but here's a basic example anyway:
vb.net Code:
Dim SelectContainerDialog As New Cjwdev.ActiveDirectory.Dialogs.SelectAdContainerDialog
If SelectContainerDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
If you don't want it to show the domain tree for the current user's domain, you can set the DomainName property to specify an alternate domain and the Username and Password properties to specify alternate credentials if required. Here's a better example showing this:
Vb.net Code:
Using SelectContainerDialog As New Cjwdev.ActiveDirectory.Dialogs.SelectAdContainerDialog
SelectContainerDialog.Title = "Please select a container"
SelectContainerDialog.DomainName = DomainBox.Text
SelectContainerDialog.Username = UsernameBox.Text
SelectContainerDialog.Password = PasswordBox.Text
If SelectContainerDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
Re: Populate TreeView with Active Directory objects
This was great. It was perfect for what I was looking for.
However, I have two questions, the first is the most important.
First:
How do I get the DistinguishedName property after a select a node. I have spent several hours trying to figure that out.
Second:
Is it possible to display / draw each node as its being added? That way, I can see my ADTreeView being built as the recursion is happeing.
Again, thanks a lot for this great example. Two three things I learn, how to connent to AD, how to recursive add AD objects to a treeview, and finally threading.
Re: Populate TreeView with Active Directory objects
I dont understand the first question, the custom TreeNode class I wrote/displayed in the above posts provides a property named DistinguishedName so you just access that property on the selected node... can you provide an example of what exactly you are trying to do and maybe I can show you how to go about it?
As for the second question, you could do that but it would require you to re-work the code I've provided because my code just adds all of the nodes to a single parent node that is stored in memory and then when that has all finished it just adds that parent node to the treeview, so you would have to change it so that instead of adding it to a node in memory it adds it to the actual treeview on screen and because that recursive function is running in a background thread that would mean you need to create another delegate etc to handle the cross thread call. Basically, I'm sure it could be done but personally I dont think its worth the hassle as it doesnt take very long (on the domains I tested it on anyway) to build the tree and its not as if the UI freezes while its being built or anything so there's little advantage to doing it.
Re: Populate TreeView with Active Directory objects
Originally Posted by chris128
I dont understand the first question, the custom TreeNode class I wrote/displayed in the above posts provides a property named DistinguishedName so you just access that property on the selected node... can you provide an example of what exactly you are trying to do and maybe I can show you how to go about it?
Thank you for the quick reply. I have add a button, that will want to set a public variable from a parent form with the DistinguishedName. Then Close the current form and return to the parent.
Currently to get past the issue, I went ahead and the DistinguishedName to the tag property.
Last edited by mikebcs; May 15th, 2009 at 01:17 PM.
Re: Populate TreeView with Active Directory objects
So whats stopping you? You've even posted showing that you can see the DistinguishedName property on the SelectedNode object so I dont understand what the problem is lol
Re: Populate TreeView with Active Directory objects
ahh right I think its because you are declaring SearchPath as a TreeNode and not an ADTreeNode which is the custom treenode based class that exposes the DistinguishedName property.
Re: Populate TreeView with Active Directory objects
Duh.... Now I see it. Great, that works perfectly!!!!!!
I do have a little more complicated question.
How does the progbar work? I don't see where you are increasing it. Also the progbar will work fine for the first time the form is load from a parent form. After I close the from and return to the parent form, and rerun that form again, the progbar does not work. Its there on the screen, but nothing happens with it.
I have tried stepping through the code, I just don't see were you increase or move the progress bar.
Again, thanks a million for helping me with the previous problem.
Re: Populate TreeView with Active Directory objects
No worries,
The progress bar I was using was set to marquee style, which means it just constantly moves in a constant loop animation, so there is no increasing etc. If you wanted to get clever you could somehow make an estimate of how many objects in AD there are to load before you make the progress bar appear and then you could just increase the progress bar value by 1% each time 1% of the objects has been loaded etc but again I think its too much work to be worth it personally.
Re: Populate TreeView with Active Directory objects
I like the marquee affect. It just nice to see that something is happening in the background.
However, when I reload the form with the progbar, The marque affect does not start again.
Load program (main form)
Click a button the load the childform with the progbar and adtreeview objects.
--- Everying workgreat. ProgBar runs, ADTreeView is built with ADTreeNodes
Drill Down through the ADTreeNodes, select the ADTreeNode I want.
Click a button that returns the selected ADTreeNode DistinguishedName and Close the child form.
Return to the main form.
Again, Click the same button to load the chilform with the progbar and adtreeview objects.
---- This were the ProgBar marquee does not run / work. The building of the ADTreeView does and show does the statuslbl indication which node its working on.
Re: Populate TreeView with Active Directory objects
If your using my sample project then you should see that in the AdTreeView1_LoadCompleted event the following happens:
vb Code:
Private Sub AdTreeView1_LoadCompleted(ByVal sender As Object, ByVal e As System.EventArgs) Handles AdTreeView1.LoadCompleted
Statuslbl.Text = "Load complete"
ProgBar.Style = ProgressBarStyle.Blocks
End Sub
So here the progress bar style is being set back to Blocks, which is the only way to stop the marquee really (as far as I know anyway) other than just making the progress bar invisible. So you just need to set it back to Marquee style using the following code before you call the LoadDirectoryObjectsAsync method in your button click event:
Re: Populate TreeView with Active Directory objects
Wonderful!!!
That solved that problem.
Thanks for all your help and advice. Your sample project was the information I needed, not only for build an AD tree, but using threads too.
What i have now discovered is that if I use the X to close the form while the treeview is building and then reopen the form before the thread completes, I get identical trees, two roots. Opps... I need to add a form unload event and abort the tread.
My main for is to copy a file to multiple computers. I have created a button to load a listbox from a textfile. I have another button that load the adtreeview form. After the builds and I select the adtreenode and use the select button. It return the distinguishedname. I use that for the root path for another connection to AD to get all the computer type objects in that path.
Of course I have a text box of what file I want to copy and a text box of where I want to copy that file too.
The very cool thing that I have been working on is using multithreading for the copy process. Original I tried to create and manage my own threads. I was using a TrackbarSlider object to set how many threads I want to create, with a max of 10. I for the life of me could not correctly figure out how to manage the treads when there where more computers than threads. I finally discovered the threadpool class. YEAH!!! I set the desired max threads for the threadpool. I have an array of all my computer names, I just use a for each statement for the list of computers, and use the threadpool.queuuserworkitem to feed the threadpool my copy funcation and computer name. Works great, I don't have to manage the treadstates.
Threading.ThreadPool.SetMaxThreads(TrBr_NumThread.Value, TrBr_NumThread.Value)
For Each item In CC
Threading.ThreadPool.QueueUserWorkItem(New Threading.WaitCallback(AddressOf Copy), item)
Next
This one section manges all my threads. (CC is my array of computer names, Copy is my function to copy the set file to each computer in the CC array)
I have learned lots with this simple little copy utility. There are something I need to fix and improve, but the core is working fine. I use a multi-line textbox to display status messages. Now with multi-treading, the status messages get out of order. Its a simple fix, but something shows the threads are running and I have multiple copy sessions running.
The last thing I need to fix is my logfile that get created and logs if each copy process is successfull or not. Currently nothing is getting written to the file, but I think it has todo with not using the delegates todo the writeline method.
Anyway, again thank you so much for the help. Its truely appreciated.
Re: Populate TreeView with Active Directory objects
That sounds good I'm glad you got it working. The ThreadPool class is something I need to play around with as I've never really tried using it much to be honest because I've always just been doing things that require one or two background threads, never loads like you are talking about.
As for writing to a log file, you shouldnt need to use a delegate to write to a file I dont think as its not a cross thread call (assuming your just trying to write information gathered from the same thread to the file anyway).
Re: Populate TreeView with Active Directory objects
Hello,
I am very interesting by your application.
I am network administrator and I begin with VB 2008 Express.
The fact is I would like to reset some local administrator passwords on computers which are in my domain.
To do that, I take your form that I modified according to my area and I just want to know :
1° How can I get the Distinguished Name of the selected node in a textbox?
e.g: if I click on the node (myComputer) which is in the parent node (Computers) which is in the domain (my.domain.com) I would like to return "LDAP://CN=myComputer,OU=Computers,DC=my,DC=domain,DC=com" in a textbox.
2° Is it possible to get Computers of a selected node in a treeview and post them directly in a listbox ?
Could you help me please ? I would appreciate that.
my actual source code :
VB Code:
Private Sub AdTreeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles AdTreeView1.AfterSelect
Re: Populate TreeView with Active Directory objects
1° How can I get the Distinguished Name of the selected node in a textbox?
The ADTreeView control I have created in this article returns an ADTreeNode when you use the SelectedNode property of the treeview, and because my ADTreeNode class has a property that gets the Distinguished Name, you can simply do this:
Re: Populate TreeView with Active Directory objects
Hi,
Sorry to answer only now but I was in holidays!
Let's go back to work...
So I tried your code but unfortunately I can't access the property 'DistinguishedName'.
An error occured and said : "DistinguishedName is not a member of System.Windows.Forms.TreeNode"
VB Code:
Private Sub AdTreeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles AdTreeView1.AfterSelect
I think that's because the property 'DistinguishedName' tried to access to the TreeNode class and not to the ADTreeNode.
But I don't know how to fix it.
Re: Populate TreeView with Active Directory objects
Hmm I was sure I made it so that the SelectedNode property returned an ADTreeNode not a normal TreeNode... but thanks for posting that workaround for other people if they have the same problem anyway
Re: Populate TreeView with Active Directory objects
If you right click on the toolbox and go to Choose Items (or it might be Select Items) then you can select the ADTreeView from somewhere within that new window that appears (its been a while since I did anything like this as I have been using WPF for the last few months). Also I think if you have a custom UserControl in your project then when you build the project it adds the control to your toolbox right at the top.
EDIT: Oh and I just checked and the project I uploaded to this thread is already targetting the .NET Framework 2.0 so I dont know why you are having problems. What exactly happens when you try and run it?
Re: Populate TreeView with Active Directory objects
Hi,
First - thanks for getting back an supporting. Much appreciated.
Since I could not open the project using VS 2005, I defined a new VB project in VS 2005 and imported the existing files.
The ADTreeView class comes upwith an error on:
Dim bgthread As New Threading.Thread(AddressOf bgthread_DoWork)
I beleive the error is because bgthread_DoWork expects a parameter. This is the error message:
Error 1 Overload resolution failed because no accessible 'New' can be called with these arguments:
'Public Sub New(start As System.Threading.ParameterizedThreadStart)': Method 'Private Sub bgthread_DoWork(RootDirectoryEntry As System.DirectoryServices.DirectoryEntry)' does not have the same signature as delegate 'Delegate Sub ParameterizedThreadStart(obj As Object)'.
'Public Sub New(start As System.Threading.ThreadStart)': Method 'Private Sub bgthread_DoWork(RootDirectoryEntry As System.DirectoryServices.DirectoryEntry)' does not have the same signature as delegate 'Delegate Sub ThreadStart()'. C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\Projects\ADTreeView\ADTreeView\ADTreeView.vb 54 13 ADTreeView
Also, form2 can not be opened, maybe because the ADTreeView is not valid.
Re: Populate TreeView with Active Directory objects
Hmm ok I'll install VS 2005 on a virtual machine later today (or possibly tomorrow) and try get it working then upload the solution
EDIT: Actually I just realised, I didnt have Option Strict On in the solution I uploaded (tut tut) and when I turn that on I get the same error you mentioned. Its pretty easy to sort out, just need to change the type casting for that DoWork method a little. One second and I'll post the code.
Re: Populate TreeView with Active Directory objects
OK try this, change the DoWork method signature to this:
vb Code:
Private Sub bgthread_DoWork(ByVal RootDirectoryEntryObject As Object)
and then add this as the first line in the DoWork method:
vb Code:
Dim RootDirectoryEntry As DirectoryEntry = DirectCast(RootDirectoryEntryObject, DirectoryEntry)
Oh and you will also need to add ToString to a couple of places as well if you have got Option Strict turned On, but VS will show you which lines they are.
Re: Populate TreeView with Active Directory objects
Hi Chris,
Well done. That solved the thread problem.
I still had to fidget with Form2 - in the end I just removed it and created it from the beginning. For some reason when you add the AdTreeView to the form it is generated as ADTreeView.ADTreeView in the designer script. I just changed it back to ADTreeView and it worked.
The next step for me is to be able to see the Users in the security groups. I wonder why did you implement this ?
Then, I need to be able to select some of the security Groups and Organization Units to generate a Filter string to get all the Users from the selected items.
If you have some code for that laying around.... :-)
Re: Populate TreeView with Active Directory objects
Being able to see the users in each group is totally different because groups do not contain child objects in the same way that containers and OUs do. You would have to use something like what I have done in this thread to get all of the users and then add them to the treeview: http://www.vbforums.com/showthread.php?t=535091
Also, this is a codebank thread and as such it is not really for asking questions so if you do still have more questions that are not strictly related to this ADTreeView control (finding out which users are in a group is not really related) then please post them in the VB.NET part of the forum and if necessary then just put a link to this thread in there so that people know what you are working with
Last edited by chris128; Jul 22nd, 2009 at 04:59 AM.
Re: Populate TreeView with Active Directory objects
Thanks.
The ADTreeView shows the hierarchy in case of containers and OUs, but not in the case of nested security groups. Is there a way to show nested security groups on the tree ?
Re: Populate TreeView with Active Directory objects
OK I have uploaded a new version of the project to the original post in this thread. The new version will retrieve the members of groups now and display them in the treeview, like so:
One thing I have not done yet is make this recursive. So if you have a group that contains another group that contains more groups and users then you will only see the first group and the group that it contains, not the groups and users within that nested group if you see what I mean.
I have also tidied up other parts of the code and made it so that the SelectedNode property returns an ADTreeNode not just a normal TreeNode now
Like I said, check the first post in this thread for a new attachment named "NewVersion-ADTreeViewInForm"
Last edited by chris128; Jul 22nd, 2009 at 02:05 PM.
Re: Populate TreeView with Active Directory objects
It seems this is what im looking for... I have some questions... do you have a new version? one that fixes the nested group? does this error also applies to OU that contains more OU that cotains some more OU... etc...
Re: Populate TreeView with Active Directory objects
No it only applies to groups. There wouldnt be much point in an Active Directory treeview if it didnt display OUs inside OUs
The groups are a special case and not something that I consider to be broken. I dont think you can even do that in the Microsoft Active Directory Users & Computers snap in, expand groups in the treeview to see their members I mean. I just added that 'feature' because someone requested it.
Re: Populate TreeView with Active Directory objects
I think I'm being thick here, I get the error: Error 1 'LoadDirectoryObjectsAsync' is not a member of 'System.Windows.Forms.TreeView'. It is based in "ADTreeView.vb".
Re: Populate TreeView with Active Directory objects
Its about time I improved this so I'll add a few new features, tidy it up, and post a new version soon - as a proper control library DLL rather than just an example project with the control in. That should make it easier for you to add it to your own program
Re: Populate TreeView with Active Directory objects
OK well this is still not 100% finished and although I have tested it, I havent tested it thoroughly yet, but here's a new version (see file attached to this post) that is built as a Control. Just add a reference to the DLL to your project. If you want to add the control to your toolbox you can just go to "Choose Items" on the toolbox and browse to the DLL.
New features include: 1. The LoadCompleted event now has a property that is passed in to it that lets you check to see if the event was raised because the load was cancelled 2. A new method named CancelLoad which lets you cancel the treeview load if it is currently in progress. This does not cancel immediately though, just the next time it starts to load a new tree in the object tree. 3. A property named ExpandGroups - set to True to make groups expandable to show their members in the treeview. Leave as the default False to just have groups show in the tree as a non-expandable item 4. 2 new properties named AuthUsername and AuthPassword that you set instead of passing the username and password in to the LoadDirectoryObjectsAsync method. 5.A LoadOnDemand property - Set to True to make the treeview just load the first 'level' of items in the root path that you specified and then only load child objects when a node is expanded. This means that the initial load is much faster but I have not yet made this work on a background thread so the control will freeze for a second when you expand a node. 6. A LoadInProgress property which you can check to see if the tree is currently being loaded in a background thread 7. A LoadCancelled property, which you can check to see if the tree is 'cancel pending'.
So if you want to try it out and let me know any problems or comments you have that would be great. Once I have finished tidying a few bits up and testing it more then I will update the first post in this thread and add it to there.
Re: Populate TreeView with Active Directory objects
I get this error when I run the form with the control:
An error occurred creating the form. See Exception.InnerException for details. The error is: Could not load file or assembly 'AdTreeViewCtrl, Version=1.3.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format.
I am a bit of a n00b so do shout of I have done something wrong ... I have not told it where to point to - just want to know if the form runs....