# VBForums CodeBank > CodeBank - Visual Basic .NET >  Populate TreeView with Active Directory objects

## chris128

*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  :Smilie: 

Here's a screenshot of the new version in action  :Cool: 




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
      MessageBox.Show(SelectContainerDialog.SelectedContainerPath)
End If
SelectContainerDialog.Dispose()

That's all there is to it  :Smilie: 

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
                MessageBox.Show(SelectContainerDialog.SelectedContainerPath)
            End If
End Using

----------


## mikebcs

This was great. It was perfect for what I was looking for.  :Big Grin: 
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.  :Confused: 

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.

----------


## 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?

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.

EDIT: Take a look at this thread on how to build a treeview node list in a background thread: http://www.vbforums.com/showthread.php?t=570020

----------


## mikebcs

> 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.

----------


## chris128

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

----------


## mikebcs

When I type

SearchPath = ADTreeView1.SelectedNode.

I can't access the FileCopy.ADTreeNode {Text = "Computers" } properties.
I Only get..

----------


## chris128

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.

----------


## mikebcs

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.

----------


## chris128

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&#37; each time 1% of the objects has been loaded etc but again I think its too much work to be worth it personally.

----------


## mikebcs

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.

How do I restart the marquee

----------


## chris128

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:

vb Code:
ProgBar.Style = ProgressBarStyle.Marquee

----------


## mikebcs

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.  :Big Grin:  (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.  :Thumb:

----------


## chris128

That sounds good  :Smilie:  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).

----------


## OlmiX

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
         'convert treeview path to LDAP path
        Dim tempPath As String = e.Node.FullPath.ToString
        Dim myCurrentPath As String
        Dim tab() As String = tempPath.Split("\")
        Dim i = tab.Length - 1
         myCurrentPath = ""
         Do While i > 0
            myCurrentPath &= tab(i) & ","
            i -= 1
        Loop
         myCurrentPath &= tab(0)
         txtCurrentPath.Text = "LDAP://" & myCurrentPath
     End Sub

----------


## chris128

*1&#176; 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:

vb Code:
TextBox1.Text = ADTreeView1.SelectedNode.DistinguishedName

That help?  :Smilie:

----------


## OlmiX

Hi,

Sorry to answer only now but I was in holidays!  :Smilie: 
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
         txtCurrentPath.Text = AdTreeView1.SelectedNode.DistinguishedName
     End Sub

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.  :Sick: 

Thanks for your time

----------


## OlmiX

OK I finally get the DN path :

Here it is my source code for some of you which could have the same problem :


VB Code:
Private Sub AdTreeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles AdTreeView1.AfterSelect
         Dim myCurrentPath As New ADTreeNode
         myCurrentPath = AdTreeView1.SelectedNode
        txtCurrentPath.Text = "LDAP://" & myCurrentPath.DistinguishedName
        GroupBox2.Enabled = True
     End Sub

Thanks a lot chris! You rock!  :Big Grin:

----------


## chris128

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  :Smilie:

----------


## arnneisp

Hi,

I'm trying to create (port) the application in (to) VB.NET 2005

If you have an exiting 2005 code, could you post it?

This may be a beginner's question - how did you add the AdTreeView class to the Form2 designer. It does not appear in the Toolbox.

In 2005 there also an error on the Thread:

Dim bgthread As New Threading.Thread(AddressOf bgthread_DoWork)

Any advise would be welcomed

Thanks.

----------


## chris128

I dont know why there would be any problems with 2005 (ie .NET 2.0) but I will convert the solution to target .NET 2.0 and see what happens..

----------


## arnneisp

That would be greate !!!

I still have this question:

This may be a beginner's question - how did you add the AdTreeView class to the Form2 designer. It does not appear in the Toolbox.

Thanks

----------


## chris128

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?

----------


## arnneisp

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.

Cheers,

Arnnei

----------


## chris128

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  :Smilie: 

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.

----------


## chris128

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.

----------


## arnneisp

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.... :-)

Many thanks.

Arnnei

----------


## chris128

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  :Smilie:

----------


## arnneisp

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 ?

----------


## chris128

Have you actually read my previous post? It explains exactly what you need to do and even has a link to an example of how to do it...

----------


## chris128

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  :Smilie:  
Like I said, check the first post in this thread for a new attachment named "NewVersion-ADTreeViewInForm"

----------


## DarkBlak

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...

----------


## chris128

No it only applies to groups. There wouldnt be much point in an Active Directory treeview if it didnt display OUs inside OUs  :Smilie: 

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.

----------


## thrillseeker

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".

It's great, apart from that! thanks!  :Smilie:

----------


## chris128

How are you using it? Is this just the example project you are using or have you made your own project and added the control in?

----------


## thrillseeker

Own project and added the control in  :Smilie:  Did take the example proj apart though ....

----------


## chris128

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  :Smilie:

----------


## thrillseeker

thanks  :Smilie:  I look forward to seeing something and thanks for writing it in the first place!

----------


## chris128

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.

Chris

----------


## thrillseeker

Nice one ... i'll try and give this a go this morning. Thanks!!  :Smilie:

----------


## thrillseeker

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....

----------


## chris128

Are you running this on a 64-bit operating system by any chance?

PS I have found a bug in it that I need to fix, so if you can hang on until tonight when I can fix this and re-upload it that would be good  :Smilie:

----------


## thrillseeker

Yes!  :Smilie:

----------


## chris128

Well then you need to change your project properties to compile to x86 rather than x64 or AnyCPU. By default when you create a new project on a 64 bit OS it will make the project a 64 bit project (well it will set it to AnyCPU but on a 64bit OS that means 64 bit) and 64 bit programs cannot work with 32 bit programs directly. My control is a 32 bit program so that is why you are getting that error.

To get around this you can make your project 32 bit (aka x86) by going into Project Properties (double click where it says My Project) and then the Compile tab on the left, then click the Advanced Compile Options button and then change the box that says AnyCPU so that it says x86. Click Save and then try and add the control again  :Smilie: 

PS look at the note I added in to my previous post as well.

----------


## thrillseeker

Thanks chris128 - I have got the control working. Very nice!  :Smilie: 

Look forward to using your updated version later.

----------


## chris128

Good stuff  :Smilie:  Let me know if you have any problems or find any bugs.

Also, when I upload the new version I will provide instructions for how to make it show the correct images for each object (basically just involves assigning an ImageList to the treeview just like you would with any other treeview but giving the images for users, computers, OUs etc a specific name)

----------


## chris128

OK the new version is now uploaded - See the original post in this thread for the download and updated information on the control.

Here is a break down of all of the methods, properties and events:

*Methods*


vb Code:
LoadDirectoryObjectsAsync("LDAP://DC=mydomain, DC=local")
Fills the treeview with objects from the active directory path passed in. This method does not block the calling thread (so it will not freeze your program while it runs) and by default it is 'recursive' - which means it will load every object it can find into the tree straight away rather than just loading one level and then loading the child objects when you expand a node. This behaviour can be changed by setting the LoadOnDemand property to True.


vb Code:
CancelLoad()
Requests that the tree stops loading objects - note that although this method will return immediately, the loading will not stop instantly. It will only cancel once the current object (including any child objects) has finished being loaded. You can test the LoadCancelled property to check to see if the control is in the "cancel pending" state and there is also a property that is passed in to the LoadCompleted event that indicates whether or not the load completed due to being cancelled.


*Properties*


vb Code:
ExpandGroups
If set to True then any groups that are shown in the tree will be expandable - expanding them will show their members but note that groups nested within groups will not be expandable.


vb Code:
LoadOnDemand
If set to True, child objects of a specific node will only be loaded when that node is expanded. This will be a synchronous operation, so it will block the UI thread while it completes. If you are on the same local network as the domain controller that is providing the responses to the AD queries then this freeze will barely even be noticeable. If you change this property after already loading (or partially loading) the tree then you should call LoadObjectsAsync again.


vb Code:
AuthUsername
The username to use when connecting to Active Directory


vb Code:
AuthPassword
The password to use when connecting to Active Directory


vb Code:
LoadInProgress
You can test this Boolean property to see if the control is currently loading objects in the background due to a call to LoadObjectsAsync


vb Code:
LoadCancelled
Indicates whether or not the current load has been requested to stop. Will be reset to False once the load has completed or has been cancelled successfully.


*Events*


vb Code:
LoadCompleted
Raised when the control has either finished loading objects or when it has been cancelled. This event may not be raised if an exception is thrown during the load (need to work on the error handling for future versions). You can test the 'e.LoadCancelled' property that is passed in to this event to see if the event was raised due to the load being cancelled. If the LoadOnDemand property has been set then this event will be raised each time child objects have finished being loaded (so every time the user expands a node)


vb Code:
LoadingObjectChanged
Raised just before the control starts to load a new object from Active Directory. You can check the 'e.CurrentObjectPath' property passed to this event to see the LDAP path for the object that is about to be loaded. Intended to be used as some kind of progress report to show that something is happening.


EDIT: See this post for properties and events new for version 1.5 : http://www.vbforums.com/showpost.php...3&postcount=67

Thats all for now - If anyone has any problems or comments then please post them  :Smilie:

----------


## DarkBlak

hi chris, thanks for answering my question....

 I'll try your new version as soon as I get back home.

For now I would like to ask a small request... is it possible for you to add a filter on your ADTreeview... for example I want to display only the Users or only the OU on my domain. thanks...

----------


## chris128

Ah yes that is a good idea, as I'm guessing most of the time that people would use something like this it is for the user to select a specific type of object. I will add that for the next version.
In the mean time, with the current control, you would have to just check the ADObjectType property of the selected node to make sure it is the correct type for what you want them to select

----------


## DarkBlak

great!!! Thanks  :Smilie:

----------


## DarkBlak

Hi Chris

How do I associate ContextMenuStrip on your ADTreeView? I have 3 different ContextMenuStrip and I want to display different CMS whenever I click a node. For example If I right click a User Node then I'm going to display the CMS for User Object and if I right click the group node then I'm going to display the CMS for Group Object same goes for OU Object. Appreciate any help, thanks!

----------


## DarkBlak

Hi Chris,

Any update on this? Thanks  :Smilie:

----------


## chris128

I havent had chance to do any more work on the control to add a filtering option yet, and as for the context menu I think you would have to just handle the NodeMouseClick event and then check to see if it is the right mouse button that has been pressed, then check the ADObjectType property of the node that was clicked and show the relevant context menu based on that.

----------


## meta

hi,

nice tool - i have a problem with the performance of it.
we have about 10000 users and groups. it takes about 2min for complete loading. i dont need the users, groups.... the only thing i need OU's.

do you have time for the filter option?

thanks

----------


## chris128

As I explained in post #46 (http://www.vbforums.com/showpost.php...7&postcount=46 ), there is a property you can set that stops it from loading the entire AD structure straight away. The property is named LoadOnDemand, so just set that to True and then each OU/container will only be loaded when someone actually tries to expand it. That should save your users from having to wait for more than a couple of seconds  :Smilie:  Let me know how it goes.

Oh and yeah I will get the filter thing done soon!  :Smilie:

----------


## meta

great!!! thx!!!! works perfect!

thanks chris!

----------


## Raivo.Metsvaht

Already found - I have to wait for filter..
--
Hi
Is there possible to hide some type of AD entries eg computers? Or only to show OU-s and Users.

----------


## chris128

I'll try and put aside some time over the next couple of days to get a filter property working and get some better error handling in there. Will update this thread when complete!

----------


## Raivo.Metsvaht

Hi
Is there possibility programmatically select a node of ADTreeview? Actually I need to select first node (domain) after loading AD.

Raivo

----------


## chris128

You would do that in the exact same way that you would do it in a normal treeview control

----------


## Raivo.Metsvaht

This is the question  how to do that?

----------


## jmcilhinney

Chris, it is against forum rules to attach binary files or archives containing binary files.  You need to remove that attachment and attach the project it was built from.

----------


## chris128

Oh sorry, I thought it was just EXE's not DLLs as well. I'll remove it and upload the solution file later today.

----------


## philipbrooke

Hi chris123, I have been using your ADtreeView and just want to say its made my life allot easier so thanks very much. Looking forward to the filter update as mentioned in previous posts.

----------


## chris128

Thanks for the positive feedback  :Smilie:  I'll try and spend some more time on this soon and get the filter option sorted.

And sorry I forgot to remove the DLL file and upload the project file JMC, I'll do it tonight!

----------


## philipbrooke

By the way, do you know of any way to catch errors. In my project I require the user to type a domain name in, the project then converts the domain name to a usable LDAP format and calls the "LoadDirectoryObjectsAsync" method. This is fine unless the user types in the wrong domain name, the project returns a "DirectoryServicesCOMException" and closes. I have tried placing the method inside a try method and using a catch as exeption to try and grab hold of the error but it does not work. Any ideas?

----------


## chris128

Yeah the Try/Catch probably doesnt work because the control uses a background thread to actually do the AD searching so the exception is not actually raised from the method that you are calling. In the next version I will make it catch all errors in the internal code and either make it just raise an event and pass the exception information to that event, or make it return exception information in the LoadCompleted event.

As a workaround for now, you could try just using the Application.UnhandledException event and checking the type of exception thrown

----------


## chris128

New version (1-5) uploaded to original post in this thread. Here's the new stuff:

*Property - ShowContainersAndOUsOnly*
Set this to true before calling the LoadDirectoryObjectsAsync method and the treeview will only show the containers and OUs (and the top level domain) rather than showing users and groups etc

*Property - LdapPrefix*
This string will be added to any LDAP queries that are done from the control internally as a result of LoadDirectoryObjectsAsync being called - it will be added after the LDAP:// but before the rest of the LDAP path, so you can use it to specify a server for all of the LDAP queries to go to (very handy if like me you want to use this from a machine that is not joined to the domain you are loading). This prefix is not applied to the path that you specify initially when calling LoadDirectoryObjectsAsync though, but because you can specify that yourself you can just add the prefix in yourself.

*Overloaded version of LoadDirectoryObjectsAsync*
There is now a parameterless version of LoadDirectoryObjectsAsync which will attempt to bind to the root of the domain your computer is joined to, rather than you having to supply a specific LDAP path for the tree to start at.

*Event - ExceptionThrown*
Raised when an exception is thrown in the background thread that loads the AD objects, so now you can handle this to see why the tree view is not loading. The original exception is passed in along with a string containing any relevant additional information.

----------


## Ginolard

Righto, so I've a form with your control on it.  I use the LoadDirectoryObjectsAsync method and......it does nothing.  Nothing added to Treeview, no errors.  Just...nothing.

Any idea what I might have not done?

----------


## chris128

lol was the first post too long to read :P There was a link in it that points you to this post for the description of all the methods and events etc:
http://www.vbforums.com/showpost.php...7&postcount=46
and this one shows the new methods/events in the updated version:
http://www.vbforums.com/showpost.php...3&postcount=67

The first method mentioned in that first link (LoadDirectoryObjectsAsync) is the one that actually loads the tree view, so that accepts a an argument that is the LDAP path you want to load  :Smilie:  Also, in the new version you can just not pass in any arguments and it will bind to the root of the domain.

----------


## Ginolard

Ah, you obviously replied to my pre-edit post  :Wink: 

I've found that method now but nothing happens.  This is what I have and the treeview remains steadfastly empty.



```
   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.AdTreeView1.ExpandGroups = True
        Me.AdTreeView1.LoadDirectoryObjectsAsync("<My_LDAP_PATH">
    End Sub
```

----------


## chris128

It might just be that it is taking a while to loop through all of the objects in AD - remember the method is Asynchronous so it works in the background. If you want to see which objects it is currently loading (to verify that it is actually doing something) then handle the _LoadingObjectChanged_ event and use the _e.CurrentObjectPath_ property that is passed in to that event. You can also handle the _ExceptionThrown_ event to see if an error is occurring in the background thread that is stopping the treeview from loading the AD structure.

If you dont want the treeview to load the entire AD structure in one go, which can take a little while, then set the _LoadOnDemand_ property to true before calling LoadDirectoryObjectsAsync.

----------


## Ginolard

Ah that was it.  Was just taking a long time.  Funnily enough, I built a Treeview for my app (see my sig) that does EXACTLY the same thing!

I didn't bother making it a separate control though.  Now I can't decide whether to stick with my code or use your control  :Wink:

----------


## chris128

ah cool, I might download your app and take a look  :Smilie: 

EDIT: Hmm when I run your application if I put my IP address in then the program freezes for quite a while (might be worth using a background thread so it doesnt do this) and then it comes up with the following error:



> System.Reflection.TargetInvocationException: An exception occurred during the operation, making the result invalid --> System.Management.ManagementException: Not Found


EDIT EDIT: Also - in the software tab it shows the Office 2007 SP2 about 7 times, shows 4 items that just have a weird symbol as the name, shows the MS Help Viewer twice, shows that I have both IE 7 and IE 8 installed (which is not possible), and a few other glitches. You might want to try using my class for enumerating software here: http://www.vbforums.com/showthread.php?t=598355 (it works on remote machines as well)  :Smilie:

----------


## Ginolard

It's a bit more limited as it doesn't show users (as that's not within the scope of my application).

----------


## chris128

Well the only issue with your treeview is that it doesnt display a + symbol next to any of the folders, but I dont know if you are too bothered about that  :Smilie:  See my previous post as well as I've edited some bugs in your app into there.

EDIT: Another issue with your app, some of the environmental variables are listed several times (TEMP and TMP in particular)
Also, the Mapped Drives section on the Summary tab only detects drives that have been mapped with the "reconnect at logon" box ticked, it does not detect drives mapped via logon script or group policy. If you want to get all mapped drives, just loop through the IO.DriveInfo.GetDrives collection and check the DriveType property of each one to see if it is a network drive - then to get the UNC path that the drive is mapped to, you can use this Windows API that I posted on my blog a while ago: http://cjwdev.wordpress.com/2009/12/...network-drive/

----------


## Ginolard

Thanks for the comments.  I'll look into the GetDrives method.  As for the environment variables, I know about that one.  It's because it lists all the environment variables for all users.

Edit:  The GetDrives method doesn't seem to support execution against remote machines.  Now that I think about it, I remember trying it way back when.  I've never found a fully reliable method for enumerating all network drives on remote machines.

Also, my Treeview does show + symbol next to the folders but only after they've been enumerated.

----------


## chadman

Wow, I love how this work, but I have one issue with it.  I am using 2010 express and compiling in 2.0.  I am not able to use the control with 2.0.  If I change it to 4.0, I can use the control and it works.  Am I missing something?

----------


## chris128

> Wow, I love how this work, but I have one issue with it.  I am using 2010 express and compiling in 2.0.  I am not able to use the control with 2.0.  If I change it to 4.0, I can use the control and it works.  Am I missing something?


Not that I can think of... the project is set to target 2.0 so it should work fine. When you are not able to use it, what exactly happens?

----------


## chadman

> Not that I can think of... the project is set to target 2.0 so it should work fine. When you are not able to use it, what exactly happens?


I think I found the issue.  2010 Express will force you to convert your old project when you first load it.  Once that's done you can go back and change the framework from 4.0 to 2.0 and it will convert it back to the 2.0 framework.  It looks like something goes wrong with that conversion back to 2.0.  It's still trying to reference some 4.0 stuff.  I used another computer that had 2005 express on it to compile the dll.  I then imported it with my 2010 project and it works!

I am having an issue with it hanging when I click on the "groups" in my domain.  We have a few hundred, but it should not take that long.  I have another OU that contains about 1300 more OU's and it loads in just a few seconds.  Any ideas?

Thanks!  Chad

----------


## chris128

Ah yeah I have seen that problem actually with 2010 not working very well when you change the target framework. It does my head in because on my work PC for some reason when I have any project target 3.5 or 2.0 it goes slow as hell so I just make them target 4.0 and it runs fine, but then when I want to work on the project at home I change it back to targeting 3.5 and it almost always screws something up  :Frown: 

As for the groups - have you got it set so that it displays members of the groups? I think the property is called ExpandGroupMembers or something like that. If so then do you mean when you try to expand a group or do you just mean when you click on a group to select it?

----------


## chadman

I think it's correct.  This is what I'm doing:

  Me.AdTreeView1.ExpandGroups = True
        Me.AdTreeView1.LoadOnDemand = True  'only load as items are clicked
        Me.AdTreeView1.Scrollable = True
        Me.AdTreeView1.LoadDirectoryObjectsAsync(strMyDomainTree)

----------


## chris128

Right so you _are_ using the expand groups option - I'm afraid there's no way I can make that part any faster as this is all the code that is responsible for getting the group members:

vb Code:
Dim Members As Object = ObjectDE.Invoke("Members", Nothing) '<<< Get members
For Each Member As Object In CType(Members, IEnumerable)  '<<< loop through members
        Dim CurrentMember As New DirectoryEntry(Member) '<<< Get directoryentry for user
        ChildNode.Nodes.Add(New AdTreeNode(CurrentMember.Name.Remove(0, 3), CurrentMember.Properties("distinguishedName").Value.ToString, GetAdObjectType(CurrentMember))) '<<< Add this node to our group node (which will later be added to the tree view)
Next
and that is the only way I know of that you can get the group members.

Do you really need to be able to expand groups? To be honest I couldn't see much use for that option when I added it. I mean if you are using this control to let the user of your application select a User or Group from AD then they dont need to be able to expand groups... they just need to know where the user or group is.

----------


## chadman

Well after 60 seconds I get this:
The CLR has been unable to transition from COM context 0x20a310 to COM context 0x20a480 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.

I really dont need to expand the groups.  I did not know it would enumerate all the members of each group for the entire groups OU.  I was hopping it would just show the members when I click on that group within the OU.  Anyway, great work and this will really save me a bunch of time:-)

----------


## chadman

Did you ever get the search filter working?

----------


## chris128

I never added the ability to specify exactly which objects you want to be visible but I did add a property that lets you choose to only show containers and OUs if that is of any use?

----------


## jay_99999

Hi Chris

Firstly, thanks for posting this.  Works a treat.  I'm just having a small issue with the icons..  In my tree view, all objects appear using the same icon (the computer icon).  I followed your instructions with extracting the icons, creating an image list and attaching this to the tree view.  Not sure what I might be doing wrong?

Cheers
Jay

----------


## chris128

You probably didn't name the images correctly then  :Smilie:  You need to set the ImageKey property of each image in the image list to the names that I mentioned in my original post. 

Having said that, I'm working on a much better version that will handle the icons for you and be faster and behave more like other .NET dialog windows.

----------


## jay_99999

It's always something simple - I had left the file extension in the name.  Look forward to checking out the new version!  Cheers, Jay

----------


## chris128

OK new version is now uploaded to the original post in this thread  :Smilie:

----------


## RKirchhof

Can't wait to try it out. Thank you!  The previous version has been a favorite tool.  I'm looking forward to updating all my programs withthis new one.

----------


## chris128

Thanks Robert  :Smilie:  let me know how it goes and if you have any feedback

I'll also be releasing another dialog window soon that can be used to select users/groups/computers from AD, similar to the native window built in to Windows shown below:

----------


## awsnap

Is it possible to start in a specified OU, such as domain.org/Computers?  I'm using this to select the container in a program that will add computers to AD, I already know they will go in this container.

----------


## chris128

> Is it possible to start in a specified OU, such as domain.org/Computers?  I'm using this to select the container in a program that will add computers to AD, I already know they will go in this container.


No I'm afraid not, but if you already know which OU they will go in, why do you need them to select an OU at all?

----------


## awsnap

Our AD structure is highly organizational under that first OU.  Also, it takes a while for this to load everything as talked about. It looks like you are looking at what children there are and then looking to see if the children have children. For me that's very time consuming. Anyway to just do the first query for each level?

----------


## awsnap

Actually there is a way.  I haven't figure out the little things about it but it's possible.

On the line in AdTreeViewForm.vb:

 Using RootDirectoryEntry As New DirectoryEntry("LDAP://" & _DomainController & ":389/" & "OU=***,DC=***,DC=***")

This will take you there BUT, will not auto load that OU, nor show the OU in the tree.  Anyone have any ideas? (This cuts out loading about 11000 users among other things for me.)

----------


## rpt124

First I would like to say this app is greate.

I have one semi challenging question. Right now I am able to view the containers and select them in AD and at the bottom of your app it shows the LDAP path of the container you have selected.

What I want to do is search for a user and get the path of the container where it is located.

So my question is, is there anyway to search for a container in AD with out haveing to visually see it, rather then having the user visually click on the OU's and have the program tell what OU they have selected?

PS. I am very very sorry about the spelling.

----------


## chris128

Yeah that's easy, but nothing to do with my example here. Just use the built in DirectorySearcher class (in the System.DirectoryServices namespace) to search for the user by their username (sAMAccountName) or whatever you want, and then get the DistinguishedName attribute from the user object as that has the full path to the object in it.

----------


## rpt124

This will find me the samAccountName of the userid that is entered by the user.



```
dirEntry = New System.DirectoryServices.DirectoryEntry("LDAP://CUSTOMER.MPSRX.com")
            dirEntry.Username = UserUsername
            dirEntry.Password = userPassword
            dirSearcher = New System.DirectoryServices.DirectorySearcher(dirEntry)
            dirSearcher.Filter = "(samAccountName=" & USERID & ")"
```

So how do I use the second part of the code? How do I compare the samAccountName to the DistinguishedName attribute from the user object as that has the full path to the object in it?

----------


## chris128

Well you don't want to compare it, you just want to read it. So as a very basic example:

vb Code:
dirEntry = New System.DirectoryServices.DirectoryEntry("LDAP://CUSTOMER.MPSRX.com")
dirEntry.Username = UserUsername
dirEntry.Password = userPassword
dirSearcher = New System.DirectoryServices.DirectorySearcher(dirEntry)
dirSearcher.Filter = "(samAccountName=" & USERID & ")"
dirSearcher.PropertiesToLoad.Add("distinguishedName")
MessageBox.Show(Cstr(dirSearcher.FindOne.Properties("distinguishedName")(0)))
That's off the top of my head and has no error handling etc in but hopefully gives you an idea

----------


## rpt124

Thanks very much for the response! Ok so I have everything working but one piece. Is there a way to move a user or object that you bind to up one or down one organizational unit with out binding to that OU directly?

The problem I am having is my company names there OU's a certain way, For example:

Company Sites
           Site OU
                 Site PC Users
The computers and User lives in that Bottom OU. I want to move the user up one OU long enough to make changes to the PC's so ther Group Policy is not applied. But I cant compare the Username to the strings in the OU's because our users are usually something like : z_123 or some type of letter_and a three digit number, Not the Site Name.

So I am looking for an easy way to just move a user Up one OU and then back down with out excatly knowing the OU's Specific name I want to move it into and then back down?

----------


## chris128

Why do you want to move them into an OU and then straight back out of it? I know you said you don't want them to be in the upper OU long enough for GPOs linked to that OU to apply to them, but why move them in there at all?

----------


## rpt124

Because the Global Policy is being applied at the lower level so I need to move the user up one level so the policy will become unapplied long enough for the application to configure the computer, once the application has configuered the computer correctly it will verify everything is correct move the user back down and reboot the computer.

----------


## chris128

Why can't the application configure the computer while the "global policy" is applied to it? What does the application need to do that the GPO is preventing? The idea of moving a user to another OU temporarily just so that something can work is a good sign of pretty bad GPO design.  If the application needs to do something on the client computer that the user does not have permission to do (due to the GPO applying to that user) then it should not be running as that user.
Also you would have to do a gpupdate on the client computer for it to detect that the user has moved to a new OU as well, otherwise it could be up to 90 minutes between you moving the user in AD and the client machine actually picking up that change and applying (or removing in this case) the new GPOs it should apply.

----------


## rpt124

The environment was configuered like this when I got here. I am just trying to work with what I have.

The application configures the laptop in 3 steps:

1. Renames it and Adds it to the domain and drops the pc in the proper OU.
Reboots
2. Moves the user up, Configures the laptop with the proper registry edits, etc.
Reboots
3. Adds the printers Moves the user back down
Reboots

Its complete.

So I need to be able to move a user up and down one level each way.

----------


## chris128

You still haven't answered the question of what exactly the application CAN'T do whilst the normal GPOs are applying. Registry edits should work fine regardless of what GPO settings you've got configured... if they didn't then half the programs your users use wouldn't work.

----------


## rpt124

The Group Policy completly locks the computer down from ther user. And that is the user that has to be logged in when configuring the laptop becuase alot of the config changes we make are user based changes not global changes to the laptop. For example, Tabbed browsing, adding printers, Verifying if adobe is installed if it is installing it, things like that.

----------


## chris128

Yes but Group Policy generally just disables the GUI for changing something so that the user cannot change it, but a program changing it would still work most of the time. Have you actually tried running your program while the user is in the regular OU?

----------


## stavris

Hi Chris,

First of all I'd like to thank you for the code.
Further I have written a small recursive routine to populate the tree and since I have seen in one of the threads that you intended to do this I thought I'd post it.
If you have already done this then ignore this thread.

P.S. I have re-used some of your code to do this.



```

 Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.Click
        m_userDomainName = ActiveDirectoryHelper.GetUserDomainName
        m_domainController = ActiveDirectoryHelper.GetSingleDomainController(m_userDomainName, m_domainUserName, m_domainUserPassword)

        Dim DomainObject As Domain = Domain.GetDomain(ActiveDirectoryHelper.GetDomainContext(m_userDomainName, m_domainUserName, m_domainUserPassword))
        Dim RootNode As New TreeNode
        Using RootDirectoryEntry As DirectoryEntry = DomainObject.GetDirectoryEntry
            RootNode.Name = CStr(RootDirectoryEntry.Properties("distinguishedName").Value).Replace("/", "\/")
            RootNode = adTree.Nodes.Add(RootNode.Name)

            CreateTree(RootDirectoryEntry, RootNode)

        End Using

    End Sub

  Private Sub CreateTree(ByVal dirEntry As DirectoryEntry, ByVal parentNode As TreeNode)

        For Each ChildObj As DirectoryEntry In dirEntry.Children
            'add it first 
            Dim childNode As New TreeNode
            childNode.Name = CStr(ChildObj.Properties("distinguishedName").Value).Replace("/", "\/")
            childNode = parentNode.Nodes.Add(childNode.Name)
            'do the recursive call
            CreateTree(ChildObj, childNode)
        Next

    End Sub
```

----------


## RKirchhof

> Can't wait to try it out. Thank you!  The previous version has been a favorite tool.  I'm looking forward to updating all my programs withthis new one.


        Dim SelectContainerDialog As New Cjwdev.ActiveDirectory.Dialogs.SelectAdContainerDialog
        SelectContainerDialog.Title = ("Choose the department OU to search for Job Role groups.")
        SelectContainerDialog.ShowDialog()

Chris the new dialog is too cool. Thank you. but, Is there a way to defalut to an expanded view?  At least the first domain node. Oh the Mouse wheel scroll doesn't seem to work for me. How do I progamatically size the control?

----------


## weirddemon

Chris,

I'm using your code in a C# project. Do you have any idea why I'd be able to load the main now, obtain the distinguished name, but not be able to load the child nodes? When I expand the very first node, it just says loading. When I debug it, it goes through the steps just like it does in the VB project.

I can show how I'm implementing it of course, but wanted to see if you knew anything off the top of your head.

*EDIT:* It's throwing an exception in the LoadAdNodes method via LoadFinished.




> Logon failure: unknown user name or bad password


But I've verified that the domain, domain controller, user, and password are all correct.

----------


## chris128

How are you specifying the username? Try using DOMAIN\Username if you were just using Username on its own

Or did it work fine with the same username and password in my VB example?

----------


## weirddemon

> How are you specifying the username? Try using DOMAIN\Username if you were just using Username on its own
> 
> Or did it work fine with the same username and password in my VB example?


I got it to work. I pasted something wrong. When I deleted everything and repasted, it worked.

But, it won't work if I leave the password as an empty string. I can't look through your code right now, but I thought if a password wasn't passed, it would still work if the current user has access. Which I remember it doing, but if I pass a an empty string to it in my project, it fails. I have to pass the password to it.

----------


## weirddemon

Chris,

Also, is there an easy way to get the attributes for each container? For the attributes you see in ADSI Edit.

EDIT: Never mind. I figure it out. You were already populating this data via ChildObject. So I created a property for AdTreeNode that is a List<string>. Then I iterated through the property list and added each one to the AdTreeNodes property list.

----------


## chris128

> I got it to work. I pasted something wrong. When I deleted everything and repasted, it worked.
> 
> But, it won't work if I leave the password as an empty string. I can't look through your code right now, but I thought if a password wasn't passed, it would still work if the current user has access. Which I remember it doing, but if I pass a an empty string to it in my project, it fails. I have to pass the password to it.


For it to use the current user's credentials you need to not set the username or password properties

----------


## weirddemon

> For it to use the current user's credentials you need to not set the username or password properties


Oh. Ok. That should be easy. One more thing, if you don't mind. This is the code I'm using to get the OU/Container attributes and their values.


C# Code:
foreach (PropertyValueCollection p in ChildObject.Properties)                                {                                    ActiveDirectoryAttributeList ADAList = new ActiveDirectoryAttributeList();                                    ADAList.Attribute = p.PropertyName;                                    ADAList.AttributeValue = p.Value.ToString();                                    ChildNode.Attributes.Add(ADAList);                                }

Your code defines ChildObject as a DirectoryEntry, with which you use to loop through the RootDirectory.Children. I then loop through all of the properties for the ChildObject to get the attributes and attribute values. I add those two data points to a list of a custom class called ActiveDirectoryAttributeList. I then add them to a property of AdTreeNode I added, called Attributes. All of that works just fine. I can see the attributes and their values during runtime, but it only pulls some attributes. Not all of them.

ADSI Edit for Engineering OU:



My app on that same OU:

----------


## chris128

Is it only pulling the ones that actually have values in them? (<Not Set> in ADSI edit means NULL)

----------


## weirddemon

> Is it only pulling the ones that actually have values in them? (<Not Set> in ADSI edit means NULL)


Forgot to come back here. Yeah, that's what's happening.

Thanks

----------


## Dazza76

Nice piece of code.  I tried to use some of the code in my app.
"Using SelectContainerDialog As New cjwdev.ActiveDirectory.Dialogs.SelectAdContainerDialog"

 but I get this error:
"Type 'cjwdev.ActiveDirectory.Dialogs.SelectAdContainerDialog' is not defined."
What am I missing?
Thanks

----------


## ppeklak

the WPF version of this would be fantastic...

----------


## weirddemon

> the WPF version of this would be fantastic...


Have you tried converting it? Shouldn't be hard at all.

----------


## MaxPower0815

> *Active Directory TreeView / Select AD Container Dialog*
> 
>  (I have a WPF version as well, if anyone wants that just let me know)


Hi,

i'm interessted in the wpf version. Where can i get it?

Greetings

Max

----------


## kkernan

I just downloaded the AD Tree View control from this thread (Thread 38 has it attached), but it's version 1.3.  Where can I find the latest version (1.5 or newer)?

Thanks, Krissy

----------


## jamiesss

Hi

I would be in trestles in the wpf version as well. Would you be able to send me the source files or code if possible?
Many thanks
Jamie

----------


## wingers

Amended version of original project with ability to show groups as well as containers/OUs - which is something I needed for my project

As per example form checkboxes to set Boolean of true or false for ShowGroups and ShowOUs properties

Defaults to false for ShowGroups and true for ShowOUs

Code amended to also show correct icon for groups as well

Changed from .NET 3.5 to .NET 4.5

Hopefully may be of use to someone....

SelectAdContainerDialog_revised.zip

----------


## Vazick

I know this is an old post but this library code still works great.  I've added a few things after changing the target framework to 4.72 to speed up the load time (since I was only interested with targeting organizationalunit and container objects):

In the AdTreeViewForm.vb file change the "LoadAdNodes" sub to this (or you could just add the entries I have highlighted to your sub):



```
Private Sub LoadAdNodes(ByVal RootNodeObject As Object)
        Dim RootNode As AdTreeNode = DirectCast(RootNodeObject, AdTreeNode)
        Dim Children As New List(Of AdTreeNode)
        Try
            Using RootDirectoryEntry As New DirectoryEntry("LDAP://" & _DomainController & ":389/" & RootNode.DistinguishedName)
                RootDirectoryEntry.AuthenticationType = AuthenticationTypes.Secure
                If Not String.IsNullOrEmpty(_Username) Then
                    RootDirectoryEntry.Username = _Username
                    RootDirectoryEntry.Password = _Password
                End If
                RootDirectoryEntry.Children.SchemaFilter.Add("organizationalUnit")
                RootDirectoryEntry.Children.SchemaFilter.Add("container")
                For Each ChildObject As DirectoryEntry In RootDirectoryEntry.Children
                        ChildObject.Children.SchemaFilter.Add("organizationalUnit")
                        ChildObject.Children.SchemaFilter.Add("container")
                        Try
                        Dim ChildObjectType As String = ChildObject.SchemaClassName
                        If ChildObjectType = "organizationalUnit" OrElse ChildObjectType = "container" Then
                            Dim ChildNode As New AdTreeNode
                            ChildNode.DisplayName = CStr(ChildObject.Properties("name").Value)
                            If ChildObjectType = "organizationalUnit" Then
                                ChildNode.Type = AdTreeNode.AdObjectType.OU
                            ElseIf ChildObjectType = "container" Then
                                ChildNode.Type = AdTreeNode.AdObjectType.Container
                            Else
                                ChildNode.Type = AdTreeNode.AdObjectType.Unknown
                            End If
                            ChildNode.DistinguishedName = CStr(ChildObject.Properties("distinguishedName").Value).Replace("/", "\/")
                            For Each ChildChildObject As DirectoryEntry In ChildObject.Children
                                ChildChildObject.Children.SchemaFilter.Add("organizationalUnit")
                                ChildChildObject.Children.SchemaFilter.Add("container")
                                Try
                                    If ChildChildObject.SchemaClassName = "organizationalUnit" OrElse ChildChildObject.SchemaClassName = "container" Then
                                        ChildNode.Nodes.Add(New AdTreeNode With {.DisplayName = "Loading..."})
                                        Exit For
                                    End If
                                Finally
                                    ChildChildObject.Dispose()
                                End Try
                            Next
                            Children.Add(ChildNode)
                        End If
                    Finally
                        ChildObject.Dispose()
                    End Try
                Next
            End Using
            Children.Sort()
            LoadFinished(True, Nothing, DirectCast(RootNodeObject, AdTreeNode), Children)
        Catch ex As Exception
            LoadFinished(False, "The following error was encountered whilst trying to load the domain objects: " & ex.Message, Nothing, Nothing)
        End Try
    End Sub
```

----------

