Programming the User-Account_Property using C#

  • Thread starter Thread starter Chris Noble
  • Start date Start date
C

Chris Noble

I am not sure that I have picked the right newsgroup for this post.

I am writing a program in C# VS 2005 to create user accounts for our
students in Active Directory.
This is to replace a program I wrote some years ago in VS6 using C++ and
ADSI.

I am trying not to use ADSI in my new program, focussing on
DirectoryServices instead.

In C# the syntax to set an Active Directory property is something like:
entry.Properties["givenName"].value="Jim"; (where entry is a
DirectoryEntry)

However for the userAccountControl property it is necessary to use a
combination of enumerated identifiers.
see http://msdn2.microsoft.com/en-us/library/aa772300.aspx
I do not want the students to be able to change a password so I need to use
ADS_UF_PASSWD_CANT_CHANGE.
This flag can be read, but not set directly as it involves setting trustee
rights etc. There is a link to an example program to set this flag but it is
in C++ and uses ADSI which I want to avoid.

Surely there must be a nice new clean way of doing this in Framework 2.0.

Is there any example C# code using DirectoryServices to set
ADS_UF_PASSWD_CANT_CHANGE?

I don't want to have to write a wrapper for my existing unmanaged code which
involved ACEs, ACLs, security descriptors etc
 
Chris Noble said:
I am not sure that I have picked the right newsgroup for this post.

I am writing a program in C# VS 2005 to create user accounts for our students in Active
Directory.
This is to replace a program I wrote some years ago in VS6 using C++ and ADSI.

I am trying not to use ADSI in my new program, focussing on DirectoryServices instead.

In C# the syntax to set an Active Directory property is something like:
entry.Properties["givenName"].value="Jim"; (where entry is a DirectoryEntry)

However for the userAccountControl property it is necessary to use a combination of
enumerated identifiers.
see http://msdn2.microsoft.com/en-us/library/aa772300.aspx
I do not want the students to be able to change a password so I need to use
ADS_UF_PASSWD_CANT_CHANGE.
This flag can be read, but not set directly as it involves setting trustee rights etc.
There is a link to an example program to set this flag but it is in C++ and uses ADSI
which I want to avoid.

Surely there must be a nice new clean way of doing this in Framework 2.0.

Is there any example C# code using DirectoryServices to set ADS_UF_PASSWD_CANT_CHANGE?

I don't want to have to write a wrapper for my existing unmanaged code which involved
ACEs, ACLs, security descriptors etc

The only way to set this "user cannot change password" property is by turning the ACE's on
the user object into an ACCESS_DENIED_ACE type ACE.
This can be done by using the DirectorySecurity class of the System.Security.AccessControl
namespace.

Willy.
 
Thanks Willy

But I'm still confused.
In my earlier version the algorithm to do this went roughly like this:
Get Security Descriptor for the object.
Using the security descriptor get the DACL for the object.
Create an ACE and add:
access mask ADS_RIGHT_DS_CONTROL_ACCESS
trustee (NT Authority\\Self)
access type ADS_ACE_TYPE_ACCESS_DENIED_OBJECT
set accessflags to to CHANGE_PASSWORD_GUID (no inheritance)
add ACE to DACL
Set Security Descriptor for the object.

Do I still need to do all this.
I am finding it difficult to translate the old terms into the new ones.
I can't see how to get to the ACEs from the DirectoryEntry


Willy Denoyette said:
Chris Noble said:
I am not sure that I have picked the right newsgroup for this post.

I am writing a program in C# VS 2005 to create user accounts for our
students in Active Directory.
This is to replace a program I wrote some years ago in VS6 using C++ and
ADSI.

I am trying not to use ADSI in my new program, focussing on
DirectoryServices instead.

In C# the syntax to set an Active Directory property is something like:
entry.Properties["givenName"].value="Jim"; (where entry is a
DirectoryEntry)

However for the userAccountControl property it is necessary to use a
combination of enumerated identifiers.
see http://msdn2.microsoft.com/en-us/library/aa772300.aspx
I do not want the students to be able to change a password so I need to
use ADS_UF_PASSWD_CANT_CHANGE.
This flag can be read, but not set directly as it involves setting
trustee rights etc. There is a link to an example program to set this
flag but it is in C++ and uses ADSI which I want to avoid.

Surely there must be a nice new clean way of doing this in Framework 2.0.

Is there any example C# code using DirectoryServices to set
ADS_UF_PASSWD_CANT_CHANGE?

I don't want to have to write a wrapper for my existing unmanaged code
which involved ACEs, ACLs, security descriptors etc

The only way to set this "user cannot change password" property is by
turning the ACE's on the user object into an ACCESS_DENIED_ACE type ACE.
This can be done by using the DirectorySecurity class of the
System.Security.AccessControl namespace.

Willy.
 
Chris Noble said:
Thanks Willy

But I'm still confused.
In my earlier version the algorithm to do this went roughly like this:
Get Security Descriptor for the object.
Using the security descriptor get the DACL for the object.
Create an ACE and add:
access mask ADS_RIGHT_DS_CONTROL_ACCESS
trustee (NT Authority\\Self)
access type ADS_ACE_TYPE_ACCESS_DENIED_OBJECT
set accessflags to to CHANGE_PASSWORD_GUID (no inheritance)
add ACE to DACL
Set Security Descriptor for the object.

Do I still need to do all this.
I am finding it difficult to translate the old terms into the new ones.
I can't see how to get to the ACEs from the DirectoryEntry

This is excatly what you need to do, except that now in v2 you have a class which makes it a
lot easier.
Take a look at the ActiveDirectorySecurity class (and not DirectorySecurity as per my
previous answer) in System.Security.AccessControl.
And here is a C# sample (scroll down the page):
http://msdn2.microsoft.com/en-gb/library/ms180915.aspx
but there are easier ways to do this using the SDDL format.

Willy.
 
Thanks Willy

Thanks - this was exactly what I needed. It works fine and its a great deal
less code than my previous version from 5/6 years ago.
When I've finished this I am unlikely to have to stray into into this area
again for a good few years. It will probably be something like VS 2010 with
Framework 10 and yet another new technology! Unless you work regularly with
a particular technology it is difficult to know what approach to take to
solve a particular problem and to find examples on the MS site. SDDL is a
new one for me. I will have to look it up.

I now have to work out how to 'mail enable' a user and create a mailbox for
them. I used CDOEXM before. I hope there is a Framework class now to handle
all this.

Thanks again for your help

Regards

Chris
 
Our network team have only just upgraded to Exchange 2003.
I assume that Exchange 2007 will have extra features and that a program
wriiten for it will probably not work with 2003.
How could I find out?

Chris
 
Chris Noble said:
Our network team have only just upgraded to Exchange 2003.
I assume that Exchange 2007 will have extra features and that a program wriiten for it
will probably not work with 2003.
How could I find out?

Chris

Chris,
I suggest you to ask this in an Exchange NG. Another option is to download a trial version
of Exchange 2007 and try it out yourself.

Willy.
 
Thanks Willy

I have got everything working now except for one small point which is
bugging me.
I want to add a user to several groups. I have several different kinds of
user with a different number of group memberships.
I have a user class which has the number of groups required and an array of
strings which hold the group names.
I have tried various approaches the last one being:

// entry is a DirectoryEntry - user.Group[n] is a String

for (int n=0;n<user.Number_Of_Groups;n++)
entry.Properties["memberOf"].Add(user.Group[n].ToString());

I can't use indexing as there may be existing group memberships. Why doesn't
this work?

I realise that I will have to check for existing group membership to avoid
duplication.

Chris
 
Willy

I am going to turn this on its head and add the users to the group rather
than add groups to the user as it looks easier. When I checked my old code
that was how I did it then.
I found this which should help me

http://msdn2.microsoft.com/en-us/library/ms180904(vs.80).aspx

Chris


Chris Noble said:
Thanks Willy

I have got everything working now except for one small point which is
bugging me.
I want to add a user to several groups. I have several different kinds of
user with a different number of group memberships.
I have a user class which has the number of groups required and an array
of strings which hold the group names.
I have tried various approaches the last one being:

// entry is a DirectoryEntry - user.Group[n] is a String

for (int n=0;n<user.Number_Of_Groups;n++)
entry.Properties["memberOf"].Add(user.Group[n].ToString());

I can't use indexing as there may be existing group memberships. Why
doesn't this work?

I realise that I will have to check for existing group membership to avoid
duplication.

Chris


Willy Denoyette said:
Chris,
I suggest you to ask this in an Exchange NG. Another option is to
download a trial version of Exchange 2007 and try it out yourself.

Willy.
 
Back
Top