Mike H. - Another Geek In Need...

WebLog

  Home  |   Contact  |   Syndication    |   Login
  58 Posts | 6 Stories | 216 Comments | 293 Trackbacks

News

Archives

Post Categories

Image Galleries

Development

Favorite Blogs

Hosting

User Groups

.Net Directory Services Programming – C# - Part 2

 

Topics Covered

Binding – How to connect to directory services and the flexibility of the bind process.

Properties – Review of the most commonly used AD properties, and a look at a few others.

 

Binding

You will remember in Part 1 that we provided a very simple code example of binding to AD and retrieving the object reference for the user object CN=Mike Hamilton. Here I want to review a little more in detail the binding process.

 

Binding The Default Server

 

Often called serverless binding, or binding to your root context, the following shows the simplest of binding calls:

 

            DirectoryEntry newEntry = new DirectoryEntry();

 

There is one major assumption here: You must be logged into the directory service (or the application you are executing must be) – otherwise the call will fail. This call will return the default server, or default root context – the server that validated your logging onto this network. I will review this in more detail shortly.

Passing The Directory (or ADsPath – we’ll review this in a later Part).

Here we pass the specific server and context that we want to bind to. Borrowing from Part 1 – you’ll remember how we bound to the specific user object.

DirectoryEntry userEntry = new DirectoryEntry(“LDAP://developer.hamilton.com/CN=Mike Hamilton,DC=developer,DC=Hamilton,DC=com”);

 

Here we specify the context of the bind. Note, this can be any server within our domain or even another domain within our directory forest.

 

Passing The Path and Credentials to Bind

 

Here we want to bind to a specific path, and provide credentials that validate we have the permission to do so. This is important as you delve into security in later Parts.

 

DirectoryEntry userEntry = new DirectoryEntry(“LDAP://developer.hamilton.com/CN=Mike Hamilton,DC=developer,DC=Hamilton,DC=com”, “<adminAccountName>”,”<adminPassword”);

 

Here you would replace adminAccountName and adminPassword with the actual credentials you want to user. Those can be the administrator account or any account that actually has permissions to perform the binding.

 

Passing The Path, Credentials, and Authentication Type

 

Not only can we bind with specific credentials, but we can also specify the authentication type we wish the directory service to use. For example:

 

DirectoryEntry userEntry = new DirectoryEntry(“LDAP://developer.hamilton.com/CN=Mike Hamilton,DC=developer,DC=Hamilton,DC=com”, “<adminAccountName>”,”<adminPassword”, AuthenticationTypes.Secure);

 

We will review the AuthenticationTypes when we review AuthenticationTypeEnum in our security review.

 

Passing a Native ADSI Object Reference

 

You will get more into this type of binding when you get into security. For now, I am presenting this for an example/reference for future reviews.

 

DirectoryEntry iAdsEntry = new DirectoryEntry(IADSObject);

 

As we move through the different presentations on this topic, we will touch on each of the bindings methods presented, offering examples / benefits of that method.

 

 

Properties in AD

 

I clarify here – AD (Active Directory). I should note that LDAP is LDAP across most directory providers. I emphasize AD here because some of the examples I will use are specific to AD insofar as the default behavior of a property or binding context. I will explain those when applicable, and will make a notation in the example conveying that it is an AD specific property or context.

 

As mentioned previously, AD (and most directory providers) has a hoard of properties that are available to the developer. Here I want to present some of the most common. What is important to note is the syntax to use when referencing a specific property. (You will remember from Part 1 that property names are spelled out using Camel-Case and single names are in lower-case only.)

 

When a user is initially created, that First Name, Last Name, Account Login Name – ever wondered what these were in AD? There are some givens when interacting with these properties – and I want to point those out first.

 

The Account Login Name is written to a few AD properties that cannot be modified via code. There are some things you can do with an AD user object, but one of the most frustrating is renaming or copying to another directory. You can move an object, and of course, delete one – but let’s move forward.

 

When the account is first created, the following properties are assigned the names you provide when creating the account (and this is assuming you created the account with a management tool / snap-in that facilitates user management – like AD Users & Computers (dsa.msc)):

 

  • First Name = givenName
  • Last Name = sn
  • Login Account Name = sAMAccountName, name, dn

 

If you wanted to retrieve these values using LDAP, and following our example in Part 1, we would do something like the following:

 

using System;

using System.DirectoryServices;

 

namespace DirectoryUtility

 

public class Main()

{

DirectoryEntry userEntry = new DirectoryEntry(“LDAP://developer.hamilton.com/CN=Mike Hamilton,OU=Developers,OU=Accounts,DC=developer,DC=hamilton,DC=com”);

 

string loginID = userEntry.Properties[“sAMAccountName”].Value.ToString();

string firstName = userEntry.Properties[“givenName”].Value.ToString();

string lastName = userEntry.Properties[“sn”].Value.ToString();

MessageBox.Show(“Login ID: “+loginID.ToString()+”\r\n Full Name: “+firstName.ToString()+” “+lastName.ToString(),”Results”);

}

 

Yes, this is a rough example, and it does not allow for exception handling. The objective was to show you how to reference just these fields.

 

Here I’ll list a few (I say a few lightly – there are dozens) properties that you will commonly use or need to use:

 

  • sAMAccountName – user ID of the account created (Note, when programmatically creating/adding users – you have control over this field – but not after the object has been added).
  • name – same value as the sAMAccountName property.
  • givenName – First Name of the user.
  • sn – or Sur Name – Last Name of the User
  • displayName – typically, the same as the name, and sAMAccountName
  • userPrincipalName – the same as name, sAMAccountName
  • co – Country
  • mail – single email address value (I’ll demonstrate how we can maintain multiple emails in another Part).
  • telephoneNumber – User’s phone number
  • description – A description of this account
  • userAccountControl – The enumerated property that we’ll use to manage the user’s account – access, password change, locked, and others.
  • wWWHomePage – User’s default homepage –optional.
  • parent – Parent owner object. For example, the name of the OU the user account is in.
  • cn – Cononical – or Common Name – usually the combination of givenName + sn (NOTE: If you have migrated from another system, like NT4 to AD 2000 – this value is the same as the name, sAMAccountName, and displayName – by default, and it cannot be changed)

 

 

How to list and view all properties available with LDAP?

 

The following code snippet shows how to step through the properties associated with a DirectoryEntry object. (NOTE: This code assumes there is a listbox named propertiesListBox on a form that we can add the properties to.)

 

private void PopulateProperties(DirectoryEntry userEntry)

{

if (userEntry!=null)

{

propertiesListBox.Clear();

foreach (string propertyName in userEntry.Properties.PropertyNames)

            propertiesListBox.Items.Add(propertyName);

}}

 

 

SUMMARY

 

I realize that a lot of this is not meat and potatoes yet, but those Parts are coming. I wanted to take the time to introduce some fundamentals because I realize there are a lot of developers out there that have not been introduced to DirectoryServices, and there is a lot to learn!

 

In our next couple of Parts we are going to look at the DirectorySearcher, the other major class in the DirectoryServices namespace, and then we’re going to look at a few basic examples of user / object management. We will start our own solution that will end up in a complete application that will allow you to connect to a directory service, list accounts and objects in that service, add accounts, add groups, and add other specific objects.

posted on Tuesday, October 04, 2005 7:45 AM

Feedback

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 11/1/2005 12:34 PM Frank H
Your articles have been very informative since I'm new to AD programming. Is there a method/way in the System.DirectoryServices to find out which groups a user belongs? Can we also get the data from an ACL for an object to find out which users or groups have access to that object through the API?
Thanks a bunch.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 11/2/2005 7:25 AM MikeH
Frank, these are good questions. I'll provide a couple of examples below. I was not going to get into ACL's/ACE's until about Part 6 - but I'll try to share a little on that now too.

First - Security Groups. How to tell what groups a user is a member of?

Using the same examples in Part 1 / Part 2 - and assuming that you have created a binding for Mike Hamilton. Now, we'll read through the 'memberOf' property and populate a list box with the groups that Mike Hamilton is a member of...

foreach (string groupName in userEntry.Properties["memberOf"])
groupsListBox.Items.Add(groupName);

That'll populate a list box called groupsListBox with the fully qualified path and name of each security group. And example output is
CN=Administrators,OU=Users,DC=developer,DC=hamilton,DC=com

If you wanted to capture these and only display the friendly name?

string [] groupNames = groupName.Split(new char [] {','});
groupNamesListBox.Items.Add(groupNames[0].SubString(3);

We simply capture a small string array of the parts of the fully qualified path, and assuming that the CN=Administrators s the first entry ([0]), we strip off the CN= and capture just the name in another list box.

Now you want to talk ACL's???

Here we step out of our normal lessons. ACL's are accessed via the IADsUser object. For example, to create an IADs reference - based on our previous examples, I'd

IADsUser iADsUser = (IADsUser)userEntry.NativeObject;

This returns the iADsUser reference and opens the door for additional API access to the object for Mike Hamilton (in this example).

You retrieve the ACL of a directory object through its 'ntSecurityDescriptor' property. For example

securityDescriptor = iADsUser.Invoke("Get", new Object [] {"ntSecurityDesciptor"}) as IADsSecurityDescriptor.

In this case, you 'could' also reference the DirectoryEntry object directly:

securityDescriptor = userEntry.Properties["ntSecurityDescriptor"].Value as IADsSecurityDescriptor;

ACL and ACE's get more involved than just these couple examples - and I was not prepared to get into these yet, but wanted to take a few minutes to share a couple examples. I will be away from home for almost 2 more weeks on my current engagement - and I will try to complete Parts 3 and 4 before then so I can get them posted.

ACL/ACE will not come until closer to the end of the series. After your query however, I may do an addition to the series, addressing security management within AD using more complex IADsUser object methods.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 11/11/2005 6:00 PM Phil Bobbett
Thankyou I have been trying to find the propertiy name to get the user login for about a week.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 12/2/2005 10:49 AM Usman (kiabaat@hotmail.com)
hi
As i was finding users of specific groups the code return me Full name of User .. i need to get only employee ids against any specific group
can any one help me please
regards,
Usman

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 12/2/2005 2:31 PM MikeH
If I understand correctly, you are able to determine the ["members"] property of a security group - and in doing so, you realized that the complete CN= is returned with the user's full name, correct?

Now, you want to find that user's login ID? (you said employee id's but I'm guessing they're the same.)

If this is the case, simply parse out the full name from the CN=, and you can try a FindOne() on the ["sn"] and ["givenName"] properties, and then read the ["sAMAccountName"] of the object found.

Hope this is helpful.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 12/6/2005 2:10 AM Frank H
Hi Mike,

I have a project where I have to deal with both asp and asp.net code. I was successful in getting authentication through active directory in the asp.net part of the code with your articles. Do you have info about authenticating users with active directory from asp files? For example, how do we access AD through asp and how can we find out which groups a user belongs to? If you have any links to such articles, that would be great. My search on the net hasn't been that fruitful. Thanks.


# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 12/11/2005 9:43 AM MikeH
Interfacing with AD from ASP.

This is a good question, and it brings to light the disadvantages of ASP vs. ASP.Net and the .Net Framework support for AD integration.

But, you CAN interface with AD from your ASP application. How? A little known, not well documented means: You can call LDAP and perform LDAP queries on AD using ADO!!!

First, if you simple Google (without the quotes) "asp ldap" you will see a lot of stuff and some decent examples on how to do this. I was not going to cover ADO connectivity in my series on Directory Services Programming because I am focusing on the System.DirectoryServices and its classes, and ADO connectivity is not necessary.

Examples? One I found is pretty decent and very straight forward - and it's straight ASP:

<%
Set con = Server.CreateObject("ADODB.Connection")
con.Provider = "ADsDSOObject"
con.Open "Active Directory Provider"
Set Com = CreateObject("ADODB.Command")
Set Com.ActiveConnection = con
Com.CommandText = "select name, sAMAccountName from 'LDAP://developer.hamilton.com/OU=Accounts,OU=Developers,DC=developer,DC=hamilton,DC=com' WHERE objectCategory='person'"
Set rs = Com.Execute
%>

This would return a recordset containing the "name" and "sAMAccountName" properties for all users in the OU=Developers OU.

Yes, there is more to research, but hopefully this will give you 1) encouragement that there is help!!!, and 2) some direction.

Please forgive any typos


# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 12/27/2005 11:54 PM alseet
Hi, I am new on AD.
I tried out the codes, but the the result I got is someting not I expected. here's my codes:
Public Function GetUserDetails(ByVal domain As String, ByVal username As String, ByVal pwd As String) As String
Dim domainAndUsername As String = domain + "\" & username
Dim UserEntry As DirectoryEntry = New DirectoryEntry(_path, domainAndUsername, pwd)
Dim propertyName As String
Dim info As String
Try
For Each propertyName In UserEntry.Properties.PropertyNames
info = info & "<br>" & propertyName & "=" & Convert.ToString(UserEntry.Properties(propertyName).Value())

Next
Catch ex As Exception
Throw ex



End Try
Return info


End Function

the result:

objectClass=System.Object[]
cn=Users
description=Default container for upgraded user accounts
distinguishedName=CN=Users,DC=my,DC=intranet
instanceType=4
whenCreated=4/20/2005 4:00:41 PM
whenChanged=4/20/2005 4:00:41 PM
uSNCreated=System.__ComObject
uSNChanged=System.__ComObject
showInAdvancedViewOnly=False
name=Users
objectGUID=System.Byte[]
systemFlags=-1946157056
objectCategory=CN=Container,CN=Schema,CN=Configuration,DC=my,DC=intranet
isCriticalSystemObject=True
dSCorePropagationData=System.Object[]
nTSecurityDescriptor=System.__ComObject

I am expecting to get User Name and memberOf.. well it's not there.. any wise one out there?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 1/23/2006 10:48 PM Ditro
Thanks for the 2nd part. Could you please post the links to other parts if available?
Also, I couldn't find the property name I was looking for in the list above.
I need to set the user's domain i.e. @my.com
This prop will show on the Accounbt tab of the AD user (user property from AD user management tool), right along the User Logon Name, showing as a drop down list of domains.
I can not seem to be able to populate this in code?
THanks again, Ditro

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 1/24/2006 4:55 AM MikeH
Ditro,

The easiest thing to do if you want to show the user's 'current' domain association is to parse the parent property which should include the full path, including the domain name.

In other words, if you have a directoryentry object called userEntry.

Parse the userEntry.Parent.Name proprety to get the domain name.

Hope that helps.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 1/24/2006 2:59 PM Ditro
Well, in this case I'm not trying to parse/get the property value, but need to set it.
I tried to set this property/attrib with the name you suggested (Parent.Name) and didn't work.
Otherwords in my c# code:
entry.Properties["sAMAccountName"].Add("Lee.Hamilton");
entry.Properties["Parent.Name"].Add("@my.com");

& I got the error of setting a wrong attribute!

Any idea? Thanks much - Ditro
BTW: are there links to other parts of your article?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 1/24/2006 3:08 PM MikeH
Ditro,

Try:

entry.Properties["sAMAccountName"].Value = "Lee Hamilton";

and so on.

If you're using the DirectoryEntry object, and not a IADsUser object.

Let me know if that helps.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 1/24/2006 4:11 PM Ditro
the code:
entry.Properties["sAMAccountName"].Add("Lee.Hamilton");
works just fine. What I meant is that the property 'Parent.Name' is invalid when I try to set:
entry.Properties["Parent.Name"].Add("@my.com");

I get no such attribute!
Thanks -Ditro


# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 1/24/2006 4:18 PM MikeH
Ditro - my apologies, I misunderstood. That is correct, the .Parent is read-only. It is used to determine the parent path.

Are you trying to add a new account to a specific OU? Or to a specific security group?

Please help me understand better what you are trying to do - and please forgive my ignorance.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 1/24/2006 4:37 PM Ditro
No problem.
I am adding a new user to an OU and setup email store. Everything works fine, but when I get the user property using AD management tool (AD Users and computers), on the 'Account' tab I notice the domain drop-down set to blank, having to click and set the value (@myserver.com) manually!

If I go ahead and do the adding procedure using this management tool manually, this drop-down is already populated!

Sorry, but thats the best I can describe it.
Still I'm not sure if this is any problem, as the user's established and owns email box/address.

Thanks again -Ditro

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 1/24/2006 4:54 PM MikeH
Ditro - I understand now.

In truth, I'm not sure just 'what' purpose that drop down serves - even though I understand what you're saying.

If you add a user to a domain context, that user belongs to that context - period. I suspect the dsa.msc snap-in may allow you to change it using the drop down, and assuming you're connected to multiple domains (DC's). But I've never worked with this so I can't really tell you one way or another.

I suspect it should be sufficient - once you've added the user to a given DC and within the desired OU - there's nothing more to do - even if this drop down is 'not' necessarily populated when you view it, if that makes any sense?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 2/15/2006 5:31 PM Alan
Hi Mike,

Your articles helped me get started with AD programming. Thank you. I'm now able to get the users belonging to a particular group as well as list the groups that a user is part of. My query now is a slightly different one.

How can I determine if a certain Active Directory group is a member of other groups?
Let’s say we have a group in Active Directory called ‘Microsoft Dallas Employees’ which contains the list of employees in Microsoft’s Dallas office. This group in turn belongs to a bigger group called Microsoft Employees. How do I use ‘Microsoft Dallas Employees’ as a search criteria and find out the other groups that this group belongs to?

I'm using ASP.NET 2.0, C# 2.0 and Active Directory 2003

-Thanks



# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 2/15/2006 5:59 PM MikeH
Alan, this is a good question, and the answer - albeit easy - is not obvious to everyone.

Each AD group has a "memberOf" property that you can check to see what groups that group is a member of!!!

HTH's

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 2/15/2006 7:55 PM Alan
Thanks Mike!! I'll test it out now.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 2/28/2006 4:12 PM Alan
Hello Mike,

Is it possible to retrieve sorted information from Active Directory? Let's say we need to get all the members of a particular group in AD. How can we get this list of members sorted by their name?

Thanks in advance

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 2/28/2006 9:21 PM MikeH
Alan, good question and I should have posted Part 3 of my series by now, but engagements have kept me from even playing Dad as much as I should.

Anyway... Sorting a return / resultset...

The good news is, there is a sorter class that facilitates this.

One of the public properties of the DirectorySearcher class is .Sort.

The SortOption class allows you to specify the property to sort on and the direction of the sort (ascending/descending).

Using Part 2 of my series, and assuming you want to create a DirectorySearcher on the "cn" property (cononical or common name). Your code might look something like:

DirectoryEntry root = new DirectoryEntry();
DirectorySearcher searcher = new DirectorySearcher(root);
searcher.Filter = "(cn=*)"; // Get all names
searcher.PropertiesToLoad.Add("name");
searcher.PropertiesToLoad.Add("mail");
// Now the SortOption....
SortOption sorter = new SortOpion();
sorter.PropertName = "name";
sorter.Direction = SortDirection.Ascending;
searcher.Sort = sorter;

That'll give you an idea - hopefully.

I apologize for not being able to post more of my development work more frequently - I've simply been on the road too much and away too long.

Please feel free to email me again if you need more info...

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 3/1/2006 5:02 AM Graeme
How can I find AD attributes given only the loginId of the user (using DirectoryServices rather than ADO)?
Thanks for the great articles.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 3/1/2006 10:09 AM MikeH
Graeme, there are a few approaches to this.

If you are running on the AD box that you know the user is a member of, you can create a default root binding, and then a DirectorySearcher object reference, and search on that name.

DirectoryEntry root = new DirectoryEntry();
DirectorySearcher searcher = new DirectorySearcher(root);
searcher.Filter("CN=<name>");
searcher.FindOne()

This is just a skeleton of the code you'll actually need, but hopefully that'll give you an idea.

Alternatively, your application may not be running on the AD box, but might be on another server and you need to bind to the AD box for that user only. In a case like this you create a DirectoryEntry reference using that user's credentials for the binding (which is one of the overloads for the class)

DirectoryEntry userEntry = new DirectoryEntry("LDAP://<fullyqualifiedservername>","username","password");

and if this call is successful (meaning the user's credentials are valid) then your object reference is specifically for that user in question.

Hope this helps...

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 3/1/2006 1:38 PM Alan
Thanks a lot Mike. Your help is very much appreciated. I think you should write a book on Active Directory programming with .Net :) It would certainly help a lot of people since there are no books out there on that topic. I'm looking forward to Part 3 of your series here. Thanks again.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 3/10/2006 4:36 PM Matt
Mike,
I was reading your posts and you have some great examples and answers. I just wanted to say nice job and thanks.
Matt

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 3/15/2006 11:14 AM Martin
Hi,

Thanks Mike for the great articles, it's been really helpful. I'm having some problems currently trying to add an optional attribute. For example, the msnpAllowDialin attribute is a boolean. I can easily change it's value (from false to true or vice-versa), or clear it. But, when I try to actually set it to true or false (and it's not set for that user), I get an error.

The same code works fine for string attributes. Here's the concerned section of my code:

de2update = new DirectoryEntry(currentPath, user, pwd);

if (setToTrue)
{
// It's a boolean type field and we want it set to true.
de2update.Properties[textBox3.Text].Add(true);
}
else if (setToFalse)
{
// It's a boolean type field and we want it set to false.
de2update.Properties[textBox3.Text].Add(false);
}
else
{
// Not a boolean, just set to the variable setToValue.
de2update.Properties[textBox3.Text].Add(setToValue);
}
de2update.CommitChanges();
de2update.Close();

The error I'm getting is the following:

The requested operation did not satisfy one or more constraints associated with the class of the object.

Thanks for any help,
Martin

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 3/16/2006 10:46 AM MikeH
Martin, without being able to step through your code with you I cannot debug the specific issue.

The textBox3.Text seems to 'not' be what you think is 'should' be in the code. The error you are getting basically boils down to your trying to add a value to something that does not exist in the specific context.

You want to set a property of type boolean, but the question is, depending on the contexdt of your directory entry at this point in the code, is that property actually in textBox3.Text?

All I can recommend at this point is stepping through the code and checking the values one step at a time. You might try hard coding the actual property to see if that works - this would allow you to isolate whether it's the casting of the value passed in textBox3.Text.

Sorry I can't be of more specific help...

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 3/16/2006 11:57 AM Martin
Thanks for your reply Mike.

I have again tested with hard-coded values, with the same results...

// The following yields: The requested operation did not satisfy one or more constraints associated with the class of the object.
de2update.Properties["msnpAllowDialin"].Add(true);

// The following works (value type is a string, not a boolean).
de2update.Properties["telephoneNumber"].Add("123-4567");

I then tried the following:

object [] myTrue = new object[1];
myTrue[0] = true;

de2update.Properties["msnpAllowDialin"].Add(myTrue);

The result is: Unspecified error.

This is easily reproduceable, just try to add a value for an optional attribute which isn't already set. It will work for a string attribute, but not for a boolean!

Thanks,
Martin

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 3/17/2006 2:41 PM MikeH
Martin, I have run into similar situations dealing with properties that have no value set - such as trying to write a null or blank string to a property, and I too have run into similar errors.

I would Google the initial "requested operation did not satisfy one or more constraints" error and see if you can run it down. I know a lot is returned on that search, but that is where I would start.

I have been stalled on working on the series I started and anticipate completing more of it this month. Perhaps I will run into more documentation on this issue during that time - and if I do I'll write up something on it.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 4/9/2006 11:11 AM Jijesh
Hello Mike,

Is it possible to get the infomation sorted by more than one field. Suppose we need to get the list of all employees sorted by first name first and then by last name. Can you please let me know how to do that?

Thanks in advance

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 4/9/2006 2:15 PM JoeP
What a great contribution you've made. I ran across your great document while researching how to manipulate AD info. For the other readers, there is a WONDERFUL resource that lists all AD attributes and their proper provider names at http://www.dotnet247.com/247reference/a.aspx?u=http://www.rlmueller.net/UserAttributes.htm
Hope this helps some!

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 4/16/2006 1:26 PM MikeH
Jijesh, I have been out of state for a couple weeks and apologize for not getting back to you sooner.

You pose a good question - I have not personally tried to handle multiple sort filters before - but I will try to get an answer and post a response for you this week.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 5/1/2006 8:41 PM MikeH
Jilesh, after some careful review - I cannot provide a sample of using the Sorter object to sort multiple columns of data. What I wound up doing is reading the data into a dataset and used the sort features there to sort the multiple columns.

You can query specifics from AD, filter the returned properties, and fairly well narrow down the scope / amount of data being returned - but the sorter object / class is fairly limited as well.

Sorry I could not be of more help.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 5/2/2006 7:40 PM Joseph
Hi, I am having the same problem here. I am trying to change the Dial-in through VB .Net program.

I tried:
strNewDSAUser.Properties("msNPAllowDialin").Add(True)

and

strNewDSAUser.Properties("msNPAllowDialin").Value = True

Neither is working, and returning any error. I found out that if dial-in = false, it returns 0. I tried
strNewDSAUser.Properties("msNPAllowDialin").Value = 1

that gives an error.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 5/2/2006 7:44 PM Joseph
I am also having errors to create the mailbox,

my code is:

Dim mailbox As CDOEXM.IMailboxStore
mailbox = CType(strNewDSAUser.NativeObject, CDOEXM.IMailboxStore)

The error is like this:

Unable to cast COM object of type 'System.__ComObject' to interface type 'CDOEXM.IMailboxStore'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{25150F41-5734-11D2-A593-00C04F990D8A}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

can you help?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 5/3/2006 4:08 PM MikeH
Joseph, I have not done much with Exchange integration and LDAP programming - however this appears that the error has to do with the strNewDSAUser not being instantiated. Have you tried stepping through your code and ensuring that this object reference is valid? I know that on many occasions I have run into something similar and it wound up being the LDAP reference was invalid - it never bound as I thought it did - but it never through an error either.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 5/25/2006 5:12 PM Eric
Hi Mike,
This is great stuff, thank you.
I want to query against a specific "alias" in our Outlook Exchange. I use your above and it works where "cn=<userid>", however I need to find a specific alias. Can you suggest an approach? I tried the DirectorySearcher but to no avail.

Thanks,
EricC


# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 5/29/2006 11:04 PM MikeH
Eric, I have not one anything specific with Exchange. If you can give me a sample of the code that is failing, perhaps I can try to help isolate an issue.

My sincere apologies for not being able to respond sooner.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 6/1/2006 6:48 PM Brian Hampson
I think the CDO.EXM error is due to lacking the MS Exchange Admin tools on your system.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 6/5/2006 3:54 PM Jessie
Mike,

Thank you for the series and you have done a great job answering reader's questions. I am currently working on a project that I need to create a delta file from active directory when certain attributes change. Do you know if there is an easy way to do it? I read some articles about using uSNChange attribute. I just wonder if there is a solution using .net. Thanks in advance!

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 6/7/2006 12:51 PM Boy
Awesome !!... Saved my day... spent 15 minutes and I am all set.. good stuff...

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 7/13/2006 4:26 AM alucky
but... how an i get all users from one group?
i was try to
LDAP://domain.net/CN=all,OU=Domain Groups,DC=domain,DC=net

but have a null result

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 7/13/2006 5:56 AM MikeH
Hi alucky,

If you simply want to enumerate through the members of a Group, you can create a binding to that group, then do a 'foreach' through the 'member' property for that group.

So, if I have a security group called AdminUsers in AD, I can do

DirectoryEntry thisGroup = new DirectoryEntry("LDAP://developer.hamilton.com/CN=AdminUsers,DC=developer,DC=hamilton,DC=com");

foreach (string userName in thisGroup.Properties["member"])
{
// Write out your users, or save them from the userName.ToString()...
}

Hope that helps...

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 8/3/2006 1:56 PM Vijay
Hi,

I am trying to add a value to objectClass property like below:

string sAdminUsername = "cn=" + AdminUserID + "," + msAdminRoot;

string sAdminPassword = AdminPassword;

string sParentConnectString = "LDAP://" + msDomain + ":" + msDefaultPort + "/" + msUserPath;



using (DirectoryEntry oOutreachOU = new DirectoryEntry(sParentConnectString, sAdminUsername, sAdminPassword, AuthenticationTypes.None))

{

// Now you can add users

using(DirectoryEntry oChild = oOutreachOU.Children.Add("CN=" + txtUsername.Text.ToString(), "user"))

{

// Make changes to the created account before applying the changes.

oChild.Properties["uid"].Value = txtUserID.Text.ToString();

oChild.Properties["sn"].Value = txtSecondName.Text.ToString();

oChild.Properties["userPassword"].Value = txtPassword.Text.ToString();



// Added on 8/1/2006

oChild.Properties["objectClass"].Add("UserAuxClass");



oChild.CommitChanges();

}

}



I am getting this exception when I added UserAuxClass to objectClass. Any help

The requested operation did not satisfy one or more constraints associated with the class of the object.

Thank you
Vijay


# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 8/3/2006 2:13 PM MikeH
Hi ViJay,

Have you tried changing the UserAuxClass to just User? I have not tried to add an objectClass type of UserAuxClass so I cannot speak directly to this - yet. I can try to research this more tonight when I get home.

Let me know...

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 8/7/2006 3:28 AM Rocky
Please let meknow how to find the email server by querying ADS using C#

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 8/8/2006 11:36 PM Kevin
I know this has been asked a couple of times, but there is one issue with your answer. "How do I get all users of a group?" And you answered, just iterate through the "member" property. While this is correct, it's not the full story. More often than not, members of a group are other groups. For example, "Building1 All Users" is a group that ultimately contains all users physically located in Building 1. However, what we really see inside that group are three other groups, "Finance", "Engineering", and "IT" because those three departments are located in that building while some other departments are located in Building 2.

So if I simply iterate over the "member" property, all I get is "Finance", "Engineering", and "IT". Not a single user object to be found. Hopefully you see where I'm going with this.

Is it possible to somehow write a DirectorySearcher filter that filters and returns all "user objects" of a group, even if that group contains groups?

I am able to set my root DirectoryEntry object to my group in question:

DirectoryEntry de = new DirectoryEntry("LDAP://trimblems.net/CN=TMS ECO Notification List,OU=Distribution Lists,OU=Chandler,DC=trimblems,DC=net");

And then if I create a DirectorySearcher with a filter like:

DirectorySearcher s = new DirectorySearcher(de, "(&(ObjectCategory=Person)(ObjectClass=user))");

Doing a .FindAll() returns zero results.

Any help or advice with this would be appreciated.

Thanks,
Kevin

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 8/13/2006 6:36 AM MikeH
Hi Kevin, I apologize for not being able respond sooner. It has been a super busy week.

Now, to pull just the users from that given Group - remove the objectCaategory=Person from your string, and capitalize the User in the objectClass=User - check the actual syntax of your query.

This should easily return all users - and if it does not, again check your syntax in the query.

HTH's...


# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 8/13/2006 6:44 AM MikeH
Joseph, and users having difficulty adding a TRUE or FALSE to a field...

I remember now a gig I was on and I was running into the same problem. Interestingly I was able to set it to TRUE by setting it to -1.

HTH's...

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 10/23/2006 10:52 AM Ramchandra
Hi,
Plz can you tell me why i am getting this exception
The value for the sort cannot be set.
Actually i want to sort the users in active directory.
Sample code
DirectorySearcher ds = new DirectorySearcher(de);
ds.Sort = new SortOption("length", SortDirection.Descending);
ds.Filter = filterPath;
If i remove the sort line or comment it then it works fine..
My mail id is : ramchandra@ec.is
You can post the information to this id

Its very urgent..

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 10/23/2006 11:49 AM MikeH
Hi Ramchandra,

Without seeing more of the code, and understanding what you are doing - it is hard to speak specifically...

Reading through this feed (I aplogize for not having any notes with me) - I found the following:


SortOption sorter = new SortOpion();
sorter.PropertName = "name";
sorter.Direction = SortDirection.Ascending;
searcher.Sort = sorter;

Here you see how the sorter binding is created, a Property defined for the search (I am not familiar with an AD Property called Length as you had), finally a direction is declared and it's bound.

HTH's...


# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 10/24/2006 2:06 AM gary
good, where is the link of part 1?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 10/24/2006 3:17 AM MikeH
Hi Gary, please see below:

http://geekswithblogs.net/mhamilton/archive/2005/09/30/55621.aspx

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 10/26/2006 10:09 AM Meet
Too far behind!!!
getting error:
Error 1 The type or namespace name 'DirectoryEntry' could not be found (are you missing a using directive or an assembly reference?)

I wrote:

DirectoryEntry entry = new DirectoryEntry("LDAP://DC=cts,DC=com", domainAndUsername, "password9!");

try
{
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=113579)";
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("description");
SearchResult result = search.FindOne();
Response.Write(result.Properties["cn"][0]);
Response.Write(result.Properties["description"][0]);
}

catch (Exception ex)
{
Response.Write(ex.Message);
Response.Write(ex.StackTrace);
}

Any suggestions?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 10/26/2006 10:15 AM MikeH
Hello Meet,

Make sure you have the directives:

using System;

using System.DirectoryServices;

At the beginning of your class.

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 11/3/2006 4:04 PM Gikote
Your tutorial really is a big help to a lot of people. Thank you for posting it.

I am trying to find all of the groups a given user is a member of. The memberof property just returns System.Object[]. I have included my sample code below. Please let me know if you have any suggestions.

private void FindADEntryData()
{
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.Filter = "(&(objectCategory=person) (objectClass=user) (sAMAccountName=" + txtSearchFor.Text.ToString() + "))";
SortOption sorter = new SortOption();
sorter.PropertyName = "sAMAccountName";
sorter.Direction = System.DirectoryServices.SortDirection.Ascending;
deSearch.Sort = sorter;
lstAD.Items.Clear();
int intFirstPass = 0;
SearchResult resEnt = deSearch.FindOne();
if ((resEnt != null) && (intFirstPass == 0))
{
intFirstPass = 1;
DirectoryEntry root = resEnt.GetDirectoryEntry();
lstUserProperties.Items.Clear();
string strAddItem = "";
foreach (string propertyName in resEnt.Properties.PropertyNames)
{
if (root.Properties[propertyName].Value != null)
{
strAddItem = propertyName + ": " + root.Properties[propertyName].Value.ToString();
lstAD.Items.Add(strAddItem);
if (propertyName == "memberof")
lblMessages.Text = root.Properties[propertyName].Value.ToString();
}
else
lstUserProperties.Items.Add(propertyName);
}
}
}


# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 11/3/2006 5:53 PM Gikote
Nevermind, I finally realized it was part of an array. Thanks again for the great articles!

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 12/4/2006 10:03 AM TSH
Hi,
I use this code to add new user to AD:
string strAccount = "ext12345";
string strUserCN = "abc #123";

deExternalUser = deExternalLDAP.Children.Add("CN=" + strUserCN.Replace("#", @"\#"), "user");
deExternalUser.Properties["SAMAccountName"].Add(strAccount);
strAction = "Commit1: " + strAccount;
deExternalUser.CommitChanges();

strAction = "Commit1a: " + strUserCN;
deExternalUser.InvokeSet("displayname", strUserCN);
strAction = "Commit2: " + strUserCN;
deExternalUser.CommitChanges();

This code works fine on 2 of 3 ADs (I have 3)
but the last one return 8000500 error (COM).
any Idea?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 12/4/2006 12:01 PM MikeH
Hi TSH,

The error code is a generic one unfortunately - indicating an unhandled / unknown exception.

With that said, I have seen the error when a value is either NULL (like one of your strings is not initialized after all) or the value is blank when it cannot be. Can you debug/step through the code and double check the values?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 12/5/2006 2:57 AM TSH
Hi Mike,
I'll check this out. one other thing is the commit timeout. Are you familier on how to do this (when the process failed it take up ot 5 minutes from the commit command to the catch entry).

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 4/10/2007 10:47 AM Satish
I have been converting to VS 2003 C# code to the VS 2005. One of my projects having the ActiveDs references is throwing 39 warnings.
Googling I see quite some are having the problem but couldnt see any solution they came up with. Is there anything we can do about getting ride of the warnings?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 4/10/2007 1:42 PM MikeH
Hi Satish,

Without seeing what the warnings are specifically, I cannot speak to whether or not - or how to - get rid of them. Warnings are 'better' than errors though. Is your code working?

# re: .Net Directory Services Programming - C# - Part 2 - DirectoryEntry Binding and AD Properties 4/11/2007 2:03 PM Satish