Geeks With Blogs

Mike H. - Another Geek In Need... WebLog

As you venture into this aspect of development, you will likely use 1 of 2 assemblies to provide you access to Active Directory (AD) or other directory services providers (DSP's). Microsoft's System.DirectoryServices is the most fundamental - providing core LDAP (lightweight directory access protocol) access to AD and its schema/components. The other is Microsoft's Active Directory Services Interface assembly (ADSI) - the ActiveDs.DLL - which is not so documented but provides a hoard of features for directory services development.

Here I am going to introduce some basic fundamentals/concepts in an effort to help you understand how these core components interact with AD from your application. In my travels down this path I have found very little in News Groups, on TechNet, or in the development community in general that address the basic fundamentals: Most of my findings are support snipets that assume you understand a lot of core components/constructs already. Most people however, do not.

As this series continues, we will cover basic AD interfaces that allow your application to interact with AD, users and objects, and update / maintain these objects. We'll gradually venture into more complex topics like security and Access Control Entries (ACE's) and Access Control Lists (ACL's) - which are the underlying interfaces/components that will provide you the ability to deliver directory services applications feature-rich in functionality and utility.

The only assumptions we'll make here are:

  • You are familiar with Visual Studio and basic development practices.
  • You understand what assemblies / references are in the IDE / application projects.
  • You are comfortable with the C# language and .Net in general.

Finally, this is not a definitive guide or approach - it is simply the musings of another Geek in Need - and I hope that conveying some of this knowledge is helpful to other developers.

So let's begin!!!

System.DirectoryServices Namespace

At the core of this namespace is the primary class DirectoryEntry. There is more here than we will cover for now, but I want to start off simple.

DirectoryEntry is the class you'll use to connect to AD, modify properties, rename or move an AD object, enumerate child objects, create child objects, delete child objects, and collect properties on objects in AD.

For this review, we'll use an AD server I have that has a DNS of developer.hamilton.com, and it is important to note the domain name components here. DirectoryEntry uses specific naming identifiers to bind and interact with directory services components. Here are some we'll address initially:

  • OU - organizationalUnitName, or organizational unit. Note however, how I spelled the initial name - using Camel Case and the fully qualified name. Throughout this series it is important to note this convention as AD uses property names in this fashion - and we will get into that in later parts.
  • CN - commonName - or cononical name. Examples are Mike Hamilton. In directory services this object is references as CN=Mike Hamilton. We'll cover this more shortly.
  • DC - domainComponent. Remember the server name above? Fully qualifying a reference to this in a binding to a DirectoryEntry is DC=developer,DC=hamilton,DC=com. I'll cover more on this in a moment too.

Lets say that Mike Hamilton is a user in AD, in the Users OU on the developer.hamilton.com domain. The following is a general reference in how you would qualify this binding in DirectoryEntry:

LDAP://developer.hamilton.com/CN=Mike Hamilton,OU=Users,DC=developer,DC=hamilton,DC=com

When binding with LDAP (or directory services) you'll notice that the connection string (for lack of a better way to describe it) is in a reverse tree order. If you were to browse this entry with Active Directory Users & Computers, you would expand developer.hamilton.com as the root node, then expand Users, and finally you would see all of the user objects in that node. If I were to create my domain user accounts in an Accounts OU, and further quantify the user objects by department (like Accounting, Development, etc). I might have something more like:

developer.hamilton.com as the root, with an OU off the root called Accounts, and within Accounts I would create OU's called Accounting, and another called Development. Now, lets say that Mike Hamilton is in the Development OU. The connection string would look like:

LDAP://developer.hamilton.com/CN=Mike Hamilton,OU=Development,OU=Accounts,DC=developer,DC=hamilton,DC=com

Now, lets look at a simple C# implementation that will bind and create a DirectoryEntry object reference to this account:

using System;

using System.DirectoryServices;

using System.Collections;

namespace DirectoryServicesAtWork

public class DirectoryUtility

{

             private DirectoryUtility()

             {

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

              }

}

 

Yes, this is a very simple example, but the above code creates an object reference called userEntry and this object will now allow you to inspect, change, and save changes to properties of the user account Mike Hamilton.

ACTIVE DIRECTORY PROPERTIES

There are a host of properties associated with objects in AD. And if you are working with a Windows 2003 forest, there are even more that were added to 2003. For now, I will review a few fundamental ones and demonstrate interaction with those properties.

Lets say I want to get the AD user ID, full name, company name, telephone number and email address of the Mike Hamilton object to display on a form? For this example, we will not create a form or the controls for this display. You will notice the textbox control references easily enough. The purpose here is to give you an example of the syntax and how to reference the appropriate properties.

There are many properties in AD, but we are going to work with only a few for now. As we get into other parts we will review more properties and how to interact with those.

Get User ID, Full Name, Company Name, Telephone Number, and Email Address.

using System;

using System.DirectoryServices;

using System.Collections;

using System.Text;

using System.Forms;

using System.ComponentModel;

namespace DirecetoryUtility

public class frmMain : System.Windows.Forms.Form          // This is the form we'll display our data on...

{

     // Here we'll skip the normal references to our controls (text boxes, etc.)

     public frmMain()

     {

          InitializeComponent();

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

          if (userEntry!=null)

          {

               txtUserID.Text = userEntry.Properties[”displayName”].Value.ToString();

               txtFullName.Text = userEntry.Properties[”givenName”].Value.ToString()+” “+userEntry.Properties[”sn”].Value.ToString();

               if (userEntry.Properties[”companyName”].Value.ToString()!=null)

                   txtCompanyName.Text = userEntry.Properties[”companyName”].Value.ToString();

               if (userEntry.Properties[”telephoneNumber”].Value.ToString!=null)

                    txtPhoneNumber.Text = userEntry.Properties[”telephoneNumber”].Value.ToString();

               if (userEntry.Properties[”mail”].Value.ToString()!=null)

                    txtMail.Text = userEntry.Properties[”mail”].Value.ToString();

           }     // End if statement

     }     // end frmMain

}     // End class

Again, this is a very simple example, but it touches on some very important aspects - Property Names in the directory.

Active Directory properties can be a single value, or a collection (array) of values for the property. For example, the userAccountControl property is an enumeration of values that maintain the account status (i.e. Disabled, User Must Change Password, Password Never Expires, and more). We will get more into properties in Part 2 of this feed.

SUMMARY

Here we have only scratched the surface of Directory Services. In the next lesson we will review more in depth the properties of AD DirectoryEntry objects, and how we can manipulate these properties for one purpose or another. We will create a sample application that displays users in a given OU, and allows you to select one from the display and view/modify the properties of that user object.

Posted on Friday, September 30, 2005 12:45 PM .Net Development | Back to top


Comments on this post: .Net Directory Services Programming - C# - Part 1

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
With regards to the userEntry.Properties[”mail”] property, can you guarentee that this will be set. When trying to find a users email address from AD I have had to dig down to the 'proxyAddresses' property, and then loop through it (multivalued) to find the default SMTP address. Unfortunately .net doesn't play nicely at this point and I have received a .net runtime error which then crashes my app.
Left by MarkW on Oct 28, 2005 9:39 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
This is a very good point. I was not going to touch on this until later on - but since you brought it up :)

Yes, if you write to .Properties["mail"].Value you can set/get the property.

Yes, the proxyAddresses property is where up to 3 addresses (and possibly more?) can be stored. The format of these within that property is, respectively:

primary@emailaddy.com
secondary@emailaddy.com
third@emailaddy.com

gets stored like:

SMTP:primary@emailaddy.com
smtp:secondary@emailaddy.com
smtp-pager:third@emailaddy.com

Notice the way the items will be saved in this property.

I was going to get into this property in a later part where we store a complete user record.

I hope this helps...
Left by Michael Hamilton on Oct 28, 2005 9:58 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
I have just started learning AD and LDAP related stuff. This is really good starting stuff for me. I thank the author of this topic.
Left by AQ on Nov 07, 2005 9:04 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Why would you not just set the attribute "pwdLastSet" to 0 to force the user to change his/her password? Are there two ways to accomplish this?
Left by Jared on Nov 17, 2005 4:50 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
That's exactly what the example does - set it to zero.

The TechNet docs state you should set it to -1 - which does just the opposite - it clears the flag.

Also, there are ways to do it with the IADsUser object reference, using the enumerated values from that class.

But the easiest way it just like you said... ["pwdLastSet"].Value = 0;

That'll do it...
Left by MikeH on Nov 17, 2005 5:18 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Sort of off subject, but is there a method in any of the DirectoryServices classes that allows you to create an Exchange mailbox for a user? I've created a .NET application to manage users in place of the AD Users & Computers snap-in. I haven't found a mechanism to mailbox-enable users, though. I have to go back to U&C to do this after the user account has been created.

Any suggestions are greatly appreciated.
Left by Jared on Nov 17, 2005 6:45 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Here is some code to create a mailbox for a user. Its in VBScript, but you can translate it to C# to do something like this:

internal static void CreateMailbox(DirectoryEntry oDE)
{
const String MDBName = "Mailbox Store (VTESTSERVER)";
const String StorageGroup = "First Storage Group";
const String Server = "VTESTSERVER";
const String AdminGroup = "First Administrative Group";
const String Organization = "First Organization";

String Parameter = "LDAP://CN=" + MDBName +
",CN=" + StorageGroup +
",CN=InformationStore" +
",CN=" + Server +
",CN=Servers" +
",CN=" + AdminGroup +
",CN=Administrative Groups" +
",CN=" + Organization +
",CN=Microsoft Exchange,CN=Services" +
",CN=Configuration," + DomainDN;
//Parameter = "CN=Mailbox Store (VTESTSERVER),CN=First Storage Group,CN=InformationStore,CN=VTESTSERVER,CN=Servers,CN=First Administrative Group,CN=Administrative Groups,CN=First Organization,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=vtestdomain,DC=local";
oDE.Invoke("CreateMailbox", Parameter); // creates mailbox in the above mailbox store
oDE.Invoke("SetInfo"); }
Left by David Jackson on Dec 12, 2005 3:58 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Thank you for the post David. I've done some work with mailboxes in AD for Exchange - and it's not fun :(
Left by MikeH on Dec 13, 2005 9:23 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
How can i change the smtpmail in the proxyAddresses.
My code is written in vbnet and i am using active directory en cdoexm.

I use the interface Irecipient (nativeobject) en read the property proxyaddresses. When i try to change a line the effect is that there is no change but an extra line is added in the proxyadresses.

example:
proxyadresses(inti) = replace(proxyadresses(inti) , oldsmtp , newstmp)


Left by Jeroen Linne on Dec 13, 2005 5:40 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
I've tried to connect AD with my code like this:
DirectoryEntry userEntry = new DirectoryEntry(”LDAP://developer.hamilton.com/CN=Mike Hamilton,OU=Developers,OU=Accounts,DC=developer,DC=hamilton,DC=com”);
and it worked,but I was not able to get the "userEntry.Properties["givenName"].Value",it seemed that can't be connected,so I checked the network and AD.etc,everything was under control,but it didn't work...
Left by Louis on Dec 15, 2005 10:39 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Louis... The LDAP string you referenced is the one I used developing the samples at home. I would guess that you changed the LDAP path to a valid one?

Sometimes the DirectoryEntry call appears to work - it doesn't generate an error - but actually does fail to connect - and that would be why the properties are not populated. A quick check is the userEntry.Name property - if the LDAP call failed - trying to read this property will return an exception and you can debug further.
Left by MikeH on Dec 18, 2005 1:38 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Jeroen,

Please see my most recent post on updating this property. Hope it is helpful...
Left by MikeH on Dec 18, 2005 4:20 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
I have not read other parts of this article, but how can we get a list of 'Organizationl Uint's in an Active Directory (all elements/sub-elements) using c#?
Thanks much for the post -Ditro
Left by Ditro on Jan 22, 2006 3:52 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Ditro, I apologize but my time has really been limited.

The easiest way is to create your binding context (the DirectoryEntry object), then create a DirectorySearcher object instance.

Set the .Filter to ("OU=*") and you'll get all OU's in that AD.

Hope that's helpful.
Left by MikeH on Jan 22, 2006 5:03 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Great! Thanks for the hint.
I'd just about tried all kinds of filters but ("OU=*") and Ended up writing a recursive method to retrieve the OU's under the root. But this is just great & simple. Not sure why these are not documented as part of the API thou.
Left by Ditro on Jan 22, 2006 5:26 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Good stuff, needed som basic info on the subject for a school projekt.
Left by Johannes Nielsen on Mar 24, 2006 6:42 AM

# .Net Directory Services Programming - C#
Requesting Gravatar...
I'm trying to find some code that will display " your password will expire in X days" does anyone know where I can find such code, or does anyone know how to do this? Thanks in advance!
Left by Frank on Mar 31, 2006 2:57 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Frank, I have been out of town - again - and haven't been able to respond.

I have resolved how to check and see if the user must change their password - but not the actual expiration property. Making this more frustrating is that there isn't a passwordExpires property.

There is an accountExpires property however, but I have not had time to play with this to see if it would be helpful.

I will still be out of town a couple more days - but I will see what I can turn up.
Left by MikeH on Apr 03, 2006 8:28 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
I figured it out. Here is the code I used:

using System.DirectoryServices;
// You must add a reference to the activeds.tlb in the system32 directory. (click, website > add reference)
// Declare that you are using the ActiveDs namespace.
using ActiveDs;

public partial class StratAccountInfo : System.Web.UI.Page
{
private static string LdapADpath = ConfigurationManager.AppSettings["LdapString"];

protected void Page_Load(object sender, EventArgs e)
{
string LogUser = User.Identity.Name.Substring(User.Identity.Name.IndexOf("\\") + 1).ToString();
lblLoggedInAs.Text = LogUser;
DirectoryEntry entry = new DirectoryEntry(LdapADpath);
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + LogUser + ")";
SearchResult LDAPresult = search.FindOne();
entry = LDAPresult.GetDirectoryEntry();

// Pulling the informtion on when the password was last changed and converting it to a LargeInteger.
LargeInteger liAcctPwdChange = entry.Properties["pwdLastSet"].Value as LargeInteger;

// Convert the highorder/loworder parts of the property pulled to a long.
long dateAcctPwdChange = (((long)(liAcctPwdChange.HighPart) << 32) + (long)liAcctPwdChange.LowPart);

// Convert FileTime to DateTime and get what today's date is.
DateTime dtNow = DateTime.Now;
// I added 90 days because I know what my password expiration is set to, if not you need to pull that information and add the number of days it is set for.
DateTime dtAcctPwdChange = DateTime.FromFileTime(dateAcctPwdChange).AddDays(90);
string strAcctPwdChange = DateTime.FromFileTime(dateAcctPwdChange).ToShortDateString();
string strAcctPwdExpires = DateTime.FromFileTime(dateAcctPwdChange).AddDays(90).ToShortDateString();

// Calculate the difference between the date the pasword was changed, and what day it is now and display the # of days.
TimeSpan time;
time = dtAcctPwdChange - dtNow;
lblPwdChangedDate.Text = strAcctPwdChange;
lblPassExp.Text = strAcctPwdExpires;
lblPwdExpDays.Text= time.Days.ToString() + " day(s)";
}
}
Left by Frank on Apr 12, 2006 5:26 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Has any one written code to pull out the password Expiry date from the Active Directory; as in the above ex 90 days is taken; i want this days to be picked from the password policy in Active Directory.
Left by Afroz Khan on Jun 08, 2006 12:37 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Afroz, I apologize for not being able to respond sooner.

I do not think there is a simple way to address this. Group Policy is not stored in the Active Directory schema. Now, the last date a password was changed 'is' stored ["pwdLastSet"] - and this is marshalled as a bigInt so it's not straight forward to read this.

Even so, reading it will simply reveal the date the password was last set (date and time actually) and this may not be helpful if you do not know the policy.

In reviewing the object model for ADSI (ActiveDs.dll) and LDAP (DirectoryServices) I cannot see a way to determine this policy from AD.

It's a great question, and if I come across more on this topic, I will blog it. Sorry I couldn't be of more help now.
Left by MikeH on Jun 10, 2006 11:22 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Is there a way that i can get my treeview to display only one folder right now it starts with the root and displays all of them and i just need it to display my mailing lists folder

any ideas
Left by Damien on Jul 31, 2006 12:42 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi Damien,

Can you be more specific about what you are trying to do as it relates to Directory Services programming? I apologize but I am not following you.
Left by MikeH on Jul 31, 2006 12:58 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Im programming in C# and have a treeview that displays my whole active directory. I'am trying to get the just my mailling lists to display instead of the whole active directory.example of this is :
private void InitTree1()
{
this.treeView1.Nodes.Clear();
this.treeView1.Nodes.Add(new TreeNode(util.RootContainer.Name, 0, 0));
//Tag TreeNode
this.treeView1.Nodes[0].Tag = new
TreeNodeInfo(util.Path, true);
int index = 0;
foreach (DirectoryEntry child in util.SharedEntry.Children)
{
index = this.treeView1.Nodes[0].Nodes.Add(new TreeNode(child.Name, 3, 4));
//Tag TreeNode
this.treeView1.Nodes[0].Nodes[index].Tag =
new TreeNodeInfo(child.Path, false);
}
this.treeView1.ExpandAll();
}

hope this help understand if not let me know i could use any help i can get.
Left by Damien on Aug 02, 2006 12:04 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi Damien,

It looks like you are trying to build a tree view of contents from a directory schema. Is this correct?

I am not sure how mailing lists are being stored in AD if that is what you are doing.

If you are wanting to display a tree view of specified schema items, you can check the objectClass of the item returned by the .Children (child) object above.

If you are creating custom entries in AD that you want to represent a mailing list, and some of these entries could be active and some not active, an option would be to use a property that is not commonly used in the object schema to set a value indicating the object is active or inactive. Then check for this in your while look - grabbing only the specified mailing list objects, and only those where this property indicates the object is active.

HTH's...
Left by MikeH on Aug 04, 2006 9:15 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
yup, its a multiline text box that displays a treeview. I'm currently working with a foreach statment to search through and find the OU that I want to display.If you have any ideas let me know or of anwhere online to find more detailed info. that would help to.
Left by Damien on Aug 04, 2006 12:23 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hello 123,

If you could provide some sample code demonstrating what you are trying to do, and convey specifically where the problem is occuring, it would be helpful.

Thanks...
Left by MikeH on Sep 12, 2006 8:36 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi MikeH,
What i want to do is have an access to DNS server using code (c#). Is there any way that i can update/add entries to DNS server ? also DNS lookup is needed for checking of existance of an entry prior to adding it. I think there should be some way in WMI or ADSI but am not sure.
Left by 123 on Sep 13, 2006 2:33 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hello 123,

I have worked via ADSI API to code against the services architecture in Windows - but it is somewhat limited insofar as the options available to you.

Specifically, I am not familiar with an API to query the DNS service for specific results. The ADSI API simply returns particulars 'about' a service - it does not extend communication with that service.

With that said, I would imagine there is an API for the Windows DNS service, yes. When you consider there are 3rd party DNS services out there you can use on Windows in place of the Windows service - I have to believe there are also API's for those services.

Sorry I could not be of more help.
Left by MikeH on Sep 13, 2006 8:30 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Mike,

Just a quick Q for a newbie, I imlpemented your code and it worked fine on our AD. However if I search for a user that doesnt exist I get the follwing error:
"An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in system.directoryservices.dll

Additional information: There is no such object on the server"

How do I check if the user exists?
Left by Sal on Sep 21, 2006 11:42 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi Sal,

If you could copy/paste the code you're working with - maybe I could offer some insight.
Left by MikeH on Sep 22, 2006 9:33 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi,
I tried the code from Frank and get the following :
System.NullReferenceException: Object reference not set to an instance of an object

long dateAcctExpiration = (((long)(liAcctExpiration.HighPart) << 32) + (long) liAcctExpiration.LowPart);

any ideas?

Thanks for any help
Left by Rendili on Sep 25, 2006 6:40 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
found it, i was setting liAcctExpiration as a long
Left by Rendili on Sep 25, 2006 7:12 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Just a huge thanks to all who contributed. I have been seraching the net for about a week to find an easy solution for a novice C# developer working with AD. This is the first article I can follow and understand.

Thanks again
Left by Clive on Dec 19, 2006 5:25 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hello there! Just came across this blog and thought I might post my question here.
I'm trying to retreive a list of users that have been locked out. Doing InvokeGet("IsAccountLocked") on a DirectoryEntry returns false results, claiming some entries are locked when in fact they are not. Any way around this?
Tnx!
Left by MuddyFox on Jan 18, 2007 3:50 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...

Just a comment:
I have also tried using this filter
(&(objectCategory=Person)(objectClass=User)(lockoutTime>=1))
but I get the exact same results, which are wrong...
Left by MuddyFox on Jan 18, 2007 6:52 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi MuddyFox,

I have used the following code to check the disabled and locked flags:

DirectoryEntry _currentUser = new DirectoryEntry();
IADsUser iADsUser = (IADsUser)_currentUser.NativeObject;

if (iADsUser.AccountDisabled == true) { yoru code if true }

if (iADsUser.IsAccountLocked == true) { your code if true }

Remember, get the native object in the iADs class and you have more flexibility insofar as checking these flags.

HTH's...
Left by MikeH on Jan 18, 2007 7:26 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Tnx for the quick reply, I was afraid this thread might be dead. :)

It has been a while since I did any half-serious development in c# so I might be a bit slow getting things running... please bear with me :)

I tried your code and it still doesn't work. I get exact same results as in previous two cases. Actual locked users and quite a number of users that are neither locked nor disabled.

And btw, users that I manually unlock after running my code still end up displayed as locked???
Left by MuddyFox on Jan 22, 2007 5:53 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hey MuddyFox,

One of my posts (http://geekswithblogs.net/mhamilton/archive/2005/10/20/57486.aspx) dealt with reading the flag that indicates that a user must change their password when they log on again.

It sounds either like 1) you may have to find a similar resolve for your solution - involving a more complex reading /setting of the flags, or 2) there is something missing that you simply need to include so you can accurately read these flags.

I have done a number of solutions where I have used these same flags - and I did not have any trouble using the iADS native object. It is very possible that you are not actually getting the native object - that an error is occuring before you attempt that binding - and what is getting returned is an error. I have run into this myself - and it is not always obvious because an exception is not actually thrown.

Can you debug-step through your code - checking the values of the objects as you bind them? In particular check the DirectoryEntry object after creating the binding - and ensure there are no properties set to an error reference, and after binding the iADS user native object, step through an ensure there are no error references in the bindings?

I will try to come up with a more simplified working code snippet and post it for you.

Regards...

MikeH...
Left by MikeH on Jan 22, 2007 6:10 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hey MuddyFox,

One of my posts (http://geekswithblogs.net/mhamilton/archive/2005/10/20/57486.aspx) dealt with reading the flag that indicates that a user must change their password when they log on again.

It sounds either like 1) you may have to find a similar resolve for your solution - involving a more complex reading /setting of the flags, or 2) there is something missing that you simply need to include so you can accurately read these flags.

I have done a number of solutions where I have used these same flags - and I did not have any trouble using the iADS native object. It is very possible that you are not actually getting the native object - that an error is occuring before you attempt that binding - and what is getting returned is an error. I have run into this myself - and it is not always obvious because an exception is not actually thrown.

Can you debug-step through your code - checking the values of the objects as you bind them? In particular check the DirectoryEntry object after creating the binding - and ensure there are no properties set to an error reference, and after binding the iADS user native object, step through an ensure there are no error references in the bindings?

I will try to come up with a more simplified working code snippet and post it for you.

Regards...

MikeH...
Left by MikeH on Jan 22, 2007 6:17 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
I really appreciate your help on this... I'll try your suggestion, but in the meantime... I ran across this article and it just might explain all the false positives I'm getting....?
Here:
http://www.mail-archive.com/activedir@mail.activedir.org/msg49139.html
Left by MuddyFox on Jan 22, 2007 6:37 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hey MuddyFox,

I have read similar posts - and thanks for that link.

However, I have successfully used the enumerations found in the DirectoryServices namespace - but it takes time to sort through these I'll admin.

Using the iADS native object is the cleanest way to work through these properties. Again, I'll try to write up a more simplified example of how to read this value accurately - I'm at work today - but I'll be home in about 12 hours.
Left by MikeH on Jan 22, 2007 6:43 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hello!

I've done some stepping through the code and casting NativeObject to IADsUser results in many attributes throwing exceptions like this one:
"+ LastFailedLogin 'iADsUser.LastFailedLogin' threw an exception of type 'System.Runtime.InteropServices.COMException' System.DateTime {System.Runtime.InteropServices.COMException}
"

On the other hand, some attributes (e.g. Name, PasswordLastChanged, isAccountLocked) return valid values.
Left by MuddyFox on Jan 22, 2007 7:28 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...

My code is still not working... I'd prefer not to be a pain in the a**, but I'm on a deadline right now so I have to ask again... any further help you can offer?
Tnx!
Left by MuddyFox on Jan 26, 2007 3:49 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi MuddyFox,

I am on a really bad schedule / dead-line today - but I will try to shed a little more light that may provide the right direction - hopefully.

In the DirectoryServices namespace there are a number of enumerated constants - for example, ADS_UF_ACCONTDISABLE, ADS_UF_LOCKOUT, ADS_UF_NORMAL_ACCOUNT - and there are many more - but these pertain to your problem at hand.

Each of these 'flags' has a hex value. The value for ADS_UF_ACCOUNTDISABLE is 0x0202, or 512 in decimal.

Here is a list of possible flags you may / may not want to work with:

public enum ADS_USER_FLAG_ENUM
{
ADS_UF_SCRIPT = 0X0001,
ADS_UF_ACCOUNTDISABLE = 0X0002,
ADS_UF_HOMEDIR_REQUIRED = 0X0008,
ADS_UF_LOCKOUT = 0X0010,
ADS_UF_PASSWD_NOTREQD = 0X0020,
ADS_UF_PASSWD_CANT_CHANGE = 0X0040,
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0X0080,
ADS_UF_TEMP_DUPLICATE_ACCOUNT = 0X0100,
ADS_UF_NORMAL_ACCOUNT = 0X0200,
ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 0X0800,
ADS_UF_WORKSTATION_TRUST_ACCOUNT = 0X1000,
ADS_UF_SERVER_TRUST_ACCOUNT = 0X2000,
ADS_UF_DONT_EXPIRE_PASSWD = 0X10000,
ADS_UF_MNS_LOGON_ACCOUNT = 0X20000,
ADS_UF_SMARTCARD_REQUIRED = 0X40000,
ADS_UF_TRUSTED_FOR_DELEGATION = 0X80000,
ADS_UF_NOT_DELEGATED = 0X100000,
ADS_UF_USE_DES_KEY_ONLY = 0x200000,
ADS_UF_DONT_REQUIRE_PREAUTH = 0x400000,
ADS_UF_PASSWORD_EXPIRED = 0x800000,
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x1000000
};

Now, I have seen a decent example in a book called Pro .Net Directory Services Programming available through aPress. The example uses a check box on the screen. If the user checks the checkbox indicating the account should be locked, the account is locked during the saveRecord function - otherwise, it is unlocked. For eg:

//Check to see if the user has elected to disable the user
if (chkDisableUser.Checked == true)
{
//Disable the user
objUser.Properties["userAccountControl"].Value = ADS_USER_FLAG_ENUM.ADS_UF_ACCOUNTDISABLE;
}
else
{
//Normal Account
objUser.Properties["userAccountControl"].Value = ADS_USER_FLAG_ENUM.ADS_UF_NORMAL_ACCOUNT;
}

You will have to call the objUser.CommitChanges() after this code.

What there is NOT a lot of out there are routines that allow you to quickly parse the .Properties["userAccountControl"].Value property/value to determine 'what' flags may / may not be set.

I have seen some examples that use <flagName> || <flagName> and other examples <flagName> AND <flagName> when reviewing the property.

I am sorry that I cannot provide working code snippets as I have not worked with this property a lot myself.

I hope this snippet proves helpful.

For now...
Left by MikeH on Jan 26, 2007 4:28 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...

Quick response is very much appreciated, I'll look this over and post the results...
Left by MuddyFox on Jan 26, 2007 5:25 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Just like to thank the author for a nice introduction to retrieving data from the AD.
Left by Jock on Jan 29, 2007 9:16 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
First of all, lemme just thank you for your time trying to straighten this out for me.

My tests show that manipulating these flags (ADS_UF_LOCKOUT included) doesn't yield an accurate list of locked users. I get a list similar to one I used to get with code posted above, but although different, it is still not accurate.

However... having hit a brick wall on this matter, I decided to google some more and this is what I finally came across:

http://dunnry.com/blog/DeterminingIfAUserIsLockedOutUsingLDAPInNET.aspx

I just want to add that this code is the only one that actually worked in my case, and it worked like a charm. Mumblings or not, it served its purpose and I can heartily recommend it...
Left by MuddyFox on Jan 31, 2007 8:16 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi,

Is it possible to know user password was expired?
I can check and calculate the expiry date before the password is expired but I cannot separate between incorrect username/password and password expired after the user password was expired.
I am writing code on .net framework 1.1
Anybody can help?
Left by Rex on Mar 21, 2007 2:31 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi Rex,

I'm not sure if this is applicable because I have not tested it. I am wondering - if the password has expired - then the user would be challenged to change their password. Correct?

I blogged here about how to see if the UserMustChangePassword is set - http://geekswithblogs.net/mhamilton/archive/2005/10/20/57486.aspx

Please let me know if that helps any.
Left by MikeH on Mar 21, 2007 7:01 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
hi, buddy,please do me a favor,help me with the below problem:
I've done the code in an IDE which is installed in a computer(in which the system is winxp) searching ad services which running on a AD_server(win2003 server),
and the codes runs properly; now the problem is once I immigrate the codes to another IDE which
is installed on a win2003 server to try to connect the same AD-service-server,the codes just can not establish
a connection,let alone to get AD-search service.
could you please come up with an answer for me ? many thanks!
Left by blueexpanse on Apr 12, 2007 9:38 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi BlueExpanse,

The first thing to check:

Is the Windows XP box a 'member' of the domain you are connecting to in your code? And, is the Windows 2003 Server - NOT a member of that domain? This can create the issue you're seeing.

What I do - and this works most of the time, and it does not matter if the machine is a member of the domain or not:

In your binding, pass the user ID and password of an account that has credentials to bind to that directory. For example,

DirectoryEntry newEntry = new DirectoryEntry();

binds to the directory ROOT of whatever domain you are a member of - or that the code is running within and it can bind. Further, this will bind using the Windows permissions of the logged on user. Instead of this, try

DirectoryEntry newEntry = new DirectoryEntry("LDAP://my.domain.com,DC=my,DC=domain,DC=com","userName","passWord");

This fully qualifies the domain to bind to, and tells AD who to bind as.

HTH's...
Left by MikeH on Apr 15, 2007 6:51 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
hi,
can anybody of the big talents here tell me,
how can we change password of user in Active directory?
i am eagerly looking towards this,
As i read posts in this bolg,
here are really great people talking..
Plz help...

Sagar
Left by Sagar on Dec 17, 2007 5:41 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi Sagar... I apologize for not being able to respond sooner.

Please check out this snippet on my new blog and see if that helps.

http://msftliveblogs.com/mhamilton/archive/2007/12/25/how-to-change-a-users-password-in-active-directory-with.aspx

HTH's...
Left by MikeH on Dec 25, 2007 6:10 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
I don’t now if this is and appropriate question for hear or not, but this is my question:

I am working with windows XPE and Windows XP clients. I need to delete a user and recreate that user to make shore there is now sensitive data left from the user deleted. I used System.DirectoryServices to delete the user account this code:

{
DeleteParam data = (DeleteParam)param;
DirectoryEntry dirEntry = null;
DirectoryEntry NewUser = null;

// delete user when existing
dirEntry = new DirectoryEntry("WinNT://" +
Environment.MachineName +
",computer", ".\\" +
mAdminUser, mAdminPassword);
try
{
// this throws when no such user
NewUser = dirEntry.Children.Find(data.Name, "User");
if(NewUser != null)
dirEntry.Children.Remove(NewUser);
}
// Catch not found exception
catch (COMException cex)
{
Debug.WriteLine(cex.Message);
}
dirEntry.Close();
}

This deletes the User from the User control panel, but do’s not delete the home directory. So I delete the home directory recursively. Then I reboot the Machine and look at the user profiles. There is a user profile called Known profile in the list. This wouldn’t be so bad except every time I delete a user get a new Known profile. And it gets better, there appears to be some kind of registry corruption associated with this as the machine will just plow up after a while. I have pad Microsoft developers to see if they now what is causing this and the answer I got back was it looks like a bug and that was it. I have spent a month with kernel debugging registry comparing with the only conclusion I can com up with is there is more to deleting a user. Do’s anyone now of any profile code tools in C#? Has anyone come across this before? Or am I just being stupid?
Left by gdwinslow on Feb 27, 2008 6:52 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi tried the following code. But getting the exception
'rootEntry.Name' threw an exception of type 'System.Runtime.InteropServices.COMException'

public LDAPClient.AuthenticationResult IsAuthenticated(string userUID, string password)
{
if (password == null || password == "")
return AuthenticationResult.BadPassword;


DirectoryEntry rootEntry = new DirectoryEntry(hostNamePath, userUID, password, AuthenticationTypes.ReadonlyServer | AuthenticationTypes.Sealing);
try
{
HttpContext.Current.Response.Write(rootEntry.Properties["Name"].Value.ToString());
// Bind to the native AdsObject to force authentication.
Object obj = rootEntry.NativeObject;
DirectorySearcher search = new DirectorySearcher(rootEntry);
search.Filter = "(uid=" + userUID + ")";
search.PropertiesToLoad.Add("uid");
SearchResult result = search.FindOne();
rootEntry.Close();
if (null == result)
return AuthenticationResult.BadPassword;
}
catch (Exception)
{
rootEntry.Close();
return AuthenticationResult.BadPassword;
}
rootEntry.Close();
return AuthenticationResult.UserAuthenticated;
}
Left by Monisha Goyal on Mar 03, 2008 6:21 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Hi

I have done coding for adding users to LDAP static groups.
The code works fine when I add users to static group which have few number of uers under it. But when try to add users to static group which have large number of users (around 70K under that group) LDAP code throws exception that "directory service is not operational".
Has anyone faced such type of issue or do you know reason behind this. If yes please let me know .
I have used DirectoryServices libraries in .net.
Left by ganesh on Mar 18, 2008 3:58 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
What if i want to List this for ALL USER in a certain OU

- Display Name
- Email
- Phone Number

lets say the domain will be calem.com

and te OU 'IT dep.' but there are more folders (OU) inside this first one... :X

The final idea is to shwo a contact list for the company users.
Left by MikeC on Apr 04, 2008 7:51 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
How to create an OU in AD?
Left by Sab on Apr 24, 2008 4:15 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Michael,
I am having the hardest time trying to update/add to the directReports attribute of a User object. I have tried multiple ways and continue to recieve an error [A constraint violation occurred.]. I've had this error before when the syntax of the DN that I was adding was incorrectly escaped but I'm sure this one is correct. Here is a snip:

public static void SetListAttribute( DirectoryEntry user, string prop, string val, bool append )
{
if ( ( val != String.Empty ) && ( val != null ) ) //you are trying to add something
{
if ( !append && user.Properties.Contains ( prop ) )
{
// clear the current value and add the new one
user.Properties[prop].RemoveAt ( 0 );
user.CommitChanges ();
}
// just append the value to the attribute
user.Properties[prop].AddRange ( new Object[] { "CN=Dandy\\, Jim,OU=OurCompany Administrators,DC=ourcompany,DC=com" } );
// I've also tried the following:::
user.Properties[prop].Add ( "CN=Dandy\\, Jim,OU=OurCompany Administrators,DC=ourcompany,DC=com" );


//user.Properties[prop][0] = val;
user.CommitChanges ();
}
}
Left by Allan on May 09, 2008 3:52 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
How i can to create a Ou?
Left by Robin on May 19, 2008 3:35 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
how to list the mail ids of people connected to a particular server?? i need this urgently
Left by bincy babu on Jun 09, 2008 1:02 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
A user is created in AD such that user needs to change password in the next logon. When the user log in for the first time into our application it should validate the username and password entered by the user and should show option for entering the new password.

I am using the following code to authenticate the user. But I am getting an exception
"Logon failure: unknown user name or bad password."

DirectoryEntry entry = new DirectoryEntry(LdapPath, UserName, Password);

DirectorySearcher searcher = new DirectorySearcher(entry);

searcher.Filter = string.Format("(userPrincipalName={0})", UserName);

SearchResult result = searcher.FindOne();

This code will work for a user who already changed his password.

I am able to chcek whether the user should change password on the next logon using the attribute "pwdLastSet". But how to authenticate the username/password user entered and then to change the password. Any help would be highly appreciated.

Thanks,
Jay
Left by Jay on Jul 21, 2008 9:40 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Just wondering is there any way to impersonate the current user if your trying to authenticate with ssl??? Seeing as how you must have a username and password to connect to a AD via ssl... I was just wondering i'm kinda stuck on this and i don't feel like adding a login box at the beginning of my app. Actually Just wondering if this is even possible!
Left by Dave on Jul 22, 2008 4:07 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
LOL! I'm such a tard sometimes!

Solved my own problem. :-D

this is how you would do it.

DirectoryEntry de = new DirectoryEntry
(ldapPath,null,null,AuthenticationTypes.SecureSocketsLayer);

since your passing null as username and password then the server just uses the current windows security context is used
I.e. the current username and password of the current user.

Hope this helps someone. :-D prolly not but at least it helped me.
Left by Dave on Jul 22, 2008 4:23 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Glad to hear it!!!

I know all too well the nuances and frustrations of sorting these things out - it's great to see others out there working it as well :)
Left by MikeH on Jul 22, 2008 9:04 PM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Respected sir
I have a dialog box. In dialog box show domain users and groups.
But our requirements is if there are several domain and in each domain have users/Groups.
Then how I fetch this information.
In our code I am using active directory code is

Utility.GetDirectoryInfo("LDAP://ABC", "Administrator", "Admin")

After that fetch the groups with this code.

Public Function getAllGroups() As TreeNode
Dim WinID As System.Security.Principal.WindowsIdentity
WinID = Security.Principal.WindowsIdentity.GetCurrent()
Dim User As New System.Security.Principal.WindowsPrincipal(WinID)
Try
Dim _AllGroups As ArrayList
Dim _AdGroup As ADGroup
_AllGroups = ADManager.Instance.LoadAllGroups

Dim i As Short = 0
For i = 0 To _AllGroups.Count - 1
_AdGroup = _AllGroups(i)
GroupNode.Nodes.Add(New TreeNode(_AdGroup.Name, 3, 3))
Next
Catch ex As Exception
Throw ex
End Try
Return GroupNode
End Function

This code is work perfectley.
But in case of multi domain is not work.So please suggest me how I fetch information in case of multi-domain and multi-domain user and group.
Please immediate reply me.
Thank
Asit Sinha
Left by Asit on Aug 05, 2008 1:48 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
How can i create new users in AD ?
Left by James on Feb 07, 2009 12:32 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Where's Part 2?
Left by Gary on May 15, 2009 9:55 AM

# Criando diretório virtual
Requesting Gravatar...
Olá, estou com um problema não estou conseguido criar um diretório virtual, aguém pode me ajudar?
Segue o código abaixo:

DirectoryEntry Parent = new DirectoryEntry("//ype/meusiste.com.br");
//DirectoryEntry Parent = new DirectoryEntry(@"//servidor/AdminSecovi/" + Id_servidor.ToString() + "/Root");
DirectoryEntry NewVirtualDir;
NewVirtualDir = Parent.Children.Add(VirtualDirName, "IIsWebVirtualDir");
NewVirtualDir.Properties["Path"][0] = Path;
NewVirtualDir.Properties["AccessScript"][0] = AccessScript;
NewVirtualDir.CommitChanges();




Dá um "erro inesperado".

O que tem de errado?

valew


Left by Sergio on Nov 18, 2009 8:00 AM

# re: .Net Directory Services Programming - C# - Part 1
Requesting Gravatar...
Good stuff...
Left by Jake on Feb 16, 2012 9:53 PM

Your comment:
 (will show your gravatar)


Copyright © Michael J. Hamilton, Sr. | Powered by: GeeksWithBlogs.net