.NET Framework - System.DirectoryServices - Constraint violation

Asked By Peter Bradley
01-Mar-07 09:58 AM
I'm trying to use System.DirectoryServices to update Active Directory from a
Web Service.  When I try to commit the changes, I get the following error
message:


My code is like this:


*** method signature and stuff ***

try
{

*** Some other code *** (assignments etc)

// Connect to the Art and Design school directory entry
DirectoryEntry de = new
DirectoryEntry("LDAP://oursever.our.domain:389/OU=Art and
Design,OU=Student,OU=Development,OU=User
Accounts,DC=internal,DC=uwic,DC=ac,DC=uk", "AnAdminUser", "apwd");

// Get the children of the directory entry and then add to the Children
collection
DirectoryEntries users = null;    // The Children Collection
DirectoryEntry user;                 // The user to Add()
if (de != null)
users = de.Children;            // Throws COMException on failure
else
throw new Exception("The Directory Entry is null");

// Add the new child, passing in the
user = users.Add("CN=asurname aforename(dv04002701)", "user");

user.Properties["distinguishedName"].Add("CN=asurname
aforename(dv04002701),OU=Art and Design,OU=Student,OU=User Accounts);

user.Properties["cn"].Add("asurname aforename(dv04002701)");
user.Properties["description"].Add(aString);
user.Properties["title"].Add(aString);
user.Properties["givenName"].Add(aForename);
user.Properties["displayName"].Add(aSurname + ", " + aForename);
user.Properties["company"].Add(anEmailAddress);
user.Properties["mail"].Add("dv04002701");
user.Properties["name"].Add(aSurname.ToLower() + " " + aForename.ToLower() +
user.Properties["userPassword"].Add(aPassword);
//user.Properties["accountDisabled"].Add(false);    // Gives error "The
specified directory service attribute or value does not exist." if included
//user.Properties["passwordExpired"].Add(false);   // Gives error "The
specified directory service attribute or value does not exist." if included
user.Properties["objectCategory"].Add(anObjectCategory);
user.Properties["objectClass"].Add(anObjectClass);
user.Properties["sAMAccountName"].Add("dv04002701");
user.Properties["instanceType"].Add(4);

user.CommitChanges();
}
catch (COMException ce)
{
string m = ce.Message; // For debug only
throw RaiseException("GetException", "WSSoapException", ce.Message,
}
catch (Exception ex)
{
string m = ex.Message; // For debug only
throw RaiseException("GetException", "WSSoapException", ex.Message,
}


According to ADSI Edit, the following fields are mandatory:

- cn
- instanceType
- objectCategory
- objectClass
- sAMAccountName

The user I give has full permissions on Active Directory.

The exception is thrown on the call to CommitChanges().

Putting CommitChanges immediately after the call to Add() gives the same
error.  Calling RefreshCache() on the DirecoryEntry (de) immediately after
the call to Add() returns with no error.

Can anyone help?



Peter
Active Directory
(1)
COMException
(1)
HRESULT
(1)
DirectoryEntry
(1)
DirectoryEntries
(1)
CommitChanges
(1)
SetPassword
(1)
RefreshCache
(1)
  Willy Denoyette [MVP] replied...
01-Mar-07 02:16 PM
Remove all this:

user.Properties["userPassword"].Add(aPassword);
//user.Properties["accountDisabled"].Add(false);    // Gives error "The
specified directory service attribute or value does not exist." if included
//user.Properties["passwordExpired"].Add(false);   // Gives error "The
specified directory service attribute or value does not exist." if included
user.Properties["objectCategory"].Add(anObjectCategory);
user.Properties["objectClass"].Add(anObjectClass);
user.Properties["instanceType"].Add(4);

These properties can't be set like this.
The password can only be set by calling the SetPassword method, using
user.Invoke("SetPassword", password );
but you can only do this after the user has been comitted.
accountDisabled can only be set by means of the userAccountControl property, something like
this will do:
user.Properties["userAccountControl"].Add(ADS_UF_NORMAL_ACCOUNT|ADS_UF_PASSWD_CANT_CHANGE);

search MSDN for the values of ADS_UF_XXXXX, or add a reference to activeds.tlb to your
project.
all other properties are added automatically and are tied to the "user" type object.

Willy.
  Peter Bradley replied...
02-Mar-07 03:03 AM
Many thanks for that Willy.

In actual fact I managed to get it to work without removing any of those.
The spec was wrong.  The objectCategory, according to the spec, was to be
set to "Person".  In fact it needed to be set to

The objectCategory, objectClass and instanceType properties all appear to
have been set correctly.

However you may well be correct about the setting of the password and the
other things.  I notice the account is disabled in AD.

Cheers


Peter
  Willy Denoyette [MVP] replied...
02-Mar-07 07:24 AM
That's correct, but you don't have to set it, it's set automatically when you add the "user"
object type to the container (as user is a person after all).


Yep, you can't set some attributes like this, some can be set through the
refer to the ADSI docs for details .

Willy.
  Peter Bradley replied...
02-Mar-07 11:35 AM
Thanks Willy.  I've got there in the end.  Certainly the accounts are now
enabled when created, and I'm pretty sure that a password has been created.
The only thing I don't appear to be able to do is to set the
userAccountControl property directly at all.  I notice that the
documentation says, "This value is set by the system".  It seems to set it
to 544 (rather than the 531 the user wanted), but I notice that a lot of
live accounts already on the system have this value (544), too.

So I'm letting my users check over the accounts I've created to see if
they're happy with them.

(Another problem solved by indirection)



Peter
  Willy Denoyette [MVP] replied...
02-Mar-07 12:48 PM
Weird, what the user wanted (544) means: normal user, account disabled, account locked-out
and logon script enabled.
what you have set is: normal account and password not required.

Don't know how you tried to set userAccountControl, but IMO you got it wrong.
Mind to post some code?

Willy.
help
Windows and Basic Authentication and Delegation. .NET Framework I am having trouble with reading Active Directory from my aspx page. IIS 6.0 is set for Windows and basic autentication for but when the server code gets to the line: srUserCol = dsUser.FindAll() There is a COMException(0x80072020) error This code works when I remove Intergrated Windows authentication from IIS 6.0 Thank you - - Jerry ASP.NET Security Discussions ASP.NET (1) SQL Server (1) IIS (1) Active Directory (1) COMException (1) SharePoint (1) SearchResultCollection (1) AuthenticationTypes (1) A couple of things: Delegation settings on the up on the delegation, disable impersonation and just use the process identity to access the directory. This may or may not work for you, depending on what you are trying to do. Best of luck! Joe K. - - Joe Kaplan-MS MVP Directory Services Programming Co-author of "The .NET Developer's Guide to Directory Services Programming" http
How to query a user's active directory site name? .NET Framework Using C#, what is the most efficient way to query a user's active directory site name? C# Discussions ArgumentOutOfRangeException (1) COMException (1) NullReferenceException (1) Office (1) DirectorySearcher (1) SAMAccountName (1) ASP.NET (1) String.Format (1 objSearch.PropertiesToLoad.Add(pstrProperty); return objSearch.FindOne().Properties[pstrProperty][0].ToString(); } } catch (System.Runtime.InteropServices.COMException) { return String.Empty; } catch (System.NullReferenceException) { return String.Empty; } catch (System.ArgumentOutOfRangeException) { return String.Empty Rae ASP.NET MVP http: / / www.markrae.net keywords: How, to, query, a, user's, active, directory, site, name? description: Using C#, what is the most efficient way to query a user
Authenticate user against active directory .NET Framework Hi All, I'm builing an application that requires domain admin access to de.NativeObject;". Any ideas as to why it's happening? Cheers, Nathan Manzi C# Discussions COMException (1) IPEndPoint (1) TokenImpersonationLevel (1) BeginAcceptTcpClient (1) EndAcceptTcpClient (1) IPAddress (1) IAsyncResult (1) WindowsIdentity (1) start by a change of your catch clause into: catch(System.Runtime.InteropServices.COMException ex) { Console.WriteLine(ex); return false; } and it will tell you why, however, there are GetStream())) { clientSide.AuthenticateAsClient(new NetworkCredential(userName, password, domain), } return id; } } Willy. keywords: Authenticate, user, against, active, directory description: Hi All, I'm builing an application that requires domain admin access to run
hab eine kleine Frage, die ihr mir sicher schnell beantworten könnt :) Es geht um Active Directory. Wie kann ich testen, ob ein Feld leer oder mit etwas gefüllt ist? Also ich ich ein Feld auslesen will, das keinen Inhalt hat, bringt er mir immer eine Fehlermeldung: COMException wurde nicht behandelt. Die Verzeichniseigenschaft wurden nicht im Cache gefunden. Ich habe schon einen Tipp wird? Mit freundlichen Grüssen Raphael Boos VB.NET - German Discussions Windows.Forms.DialogResult.Cancel (1) Active Directory (1) COMException (1) Reference.ContainsKey (1) DialogResult.Cancel (1) Console.WriteLine (1) System.EventArgs (1) EventArgs (1 aber finden. - - Gruß Scotty Ja ich will die Datei nachher weiter verwenden. Und wenn im Active Directory bei den Initialen nichts eingetragen ist, macht es ja nichts aus wenn man "" ( = leer) angibt