Link to home
Start Free TrialLog in
Avatar of NickMalloy
NickMalloyFlag for United States of America

asked on

Working with the Active Directory

I have the following code that is suppose to be used to add a user to the active directory using directoryservices. My problem is that my server requires certain parameters for a password when a user is created. Is there anyway to set the password at the same time when the user is actually created. Right now when I try to move the password setting under the UserAccountControl I get an object doesn't exist.

Dim objDE As New System.DirectoryServices.DirectoryEntry(CStr(Application("")))
 Dim objUser As  DirectoryServices.DirectoryEntry = New DirectoryServices.DirectoryEntry
            objUser = objDE.children.Add("cn=" & login.text & "","user")
             objUser.Properties("sAMAccountName").add(login.text)
             objUser.Properties("sn").add(lname.text)
             objUser.Properties("displayName").add(lname.text & "," & fname.text)
             objUser.Properties("telephoneNumber").add(tel.text)
             objUser.Properties("mail").add(email.text)
            objUser.Properties("userAccountControl").add(512)
            objUser.commitChanges()
            objUser.Invoke("setPassword", "sweet98")
            objUser.commitChanges()
Avatar of ihenry
ihenry

Can you post here the exception stack trace?
Avatar of NickMalloy

ASKER


Stack Trace:


[UnauthorizedAccessException: General access denied error
]
   System.DirectoryServices.Interop.IAds.SetInfo() +0
   System.DirectoryServices.DirectoryEntry.CommitChanges() +37
   ASP.addaduser_aspx.add_ad(Object Source, EventArgs E) in D:\Intranet\Mystuff\Mystuff\addaduser.aspx:27
   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +108
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +57
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +18
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
   System.Web.UI.Page.ProcessRequestMain() +1277

 
stack trace when the setpassword is moved. up



[COMException (0x80072030): There is no such object on the server.]

[TargetInvocationException: Exception has been thrown by the target of an invocation.]
   System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters) +0
   System.RuntimeType.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParameters) +473
   System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args) +29
   System.DirectoryServices.DirectoryEntry.Invoke(String methodName, Object[] args) +106
   ASP.addaduser_aspx.add_ad(Object Source, EventArgs E) in D:\Intranet\Mystuff\Mystuff\addaduser.aspx:27
   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +108
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +57
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +18
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
   System.Web.UI.Page.ProcessRequestMain() +1277

 

Generally, when create a new user account you want to do it like this

Create the object and CommitChanges
Then, call SetPassword and CommitChanges
Then, set userAccountControl to enable the object and call CommitChanges one last time.

Is the user account created? what is line 27 in the adduser.aspx?
no it doesn't create a user.
Line 27:  objUser.commitChanges()
this?

objUser.commitChanges()
objUser.Invoke("setPassword", "sweet98")
objUser.commitChanges()     <-- line 27?
NickMalloy,

You have 2 lines which have objUser.commitChanges().
That is to set the password if I am correct
Are you saying it should look like this?

objUser = objDE.children.Add("cn=" & login.text & "","user")
             objUser.Properties("sAMAccountName").add(login.text)
             objUser.Properties("sn").add(lname.text)
             objUser.Properties("displayName").add(lname.text & "," & fname.text)
             objUser.Properties("telephoneNumber").add(tel.text)
             objUser.Properties("mail").add(email.text)
            objUser.commitChanges()
            objUser.Invoke("setPassword", "sweet98")
            objUser.commitChanges()
            objUser.Properties("userAccountControl").add(512)
            objUser.commitChanges()
What I wanted to know is at which line exactly the exception is thrown. There're only 2 possibilities

objUser.Properties("mail").add(email.text)
objUser.Properties("userAccountControl").add(512)
objUser.commitChanges()     <-- here
objUser.Invoke("setPassword", "sweet98")
objUser.commitChanges()     <-- or here

But since no user account created during execution so most likely the first CommitChange that giving you the problem.

>> Are you saying it should look like this?
Almost exactly yes, except ADS_UF_NORMAL_ACCOUNT ( =512 ) can be executed right before the first CommitChange and removal of ADS_UF_ACCOUNTDISABLE right before the last CommitChange.

But it seems your problem is likely more on security problem. Tell me more on what authentication for the web app, windows or forms authentication? if windows do you enable IIS "Integrated Windows Authentication"? And are you sure the current user windows login account has proper permission rights?
When the SetPassword is moved up, it seems you have another problem.

I'm not sure if this line works
objUser.Invoke("setPassword", "sweet98")

I'm using the following lines and it works great
objUser.Invoke( "setPassword", New Object() { "sweet98" } )
The first one is throwing it.
objUser.Properties("mail").add(email.text)
objUser.Properties("userAccountControl").add(512)
objUser.commitChanges()     <-- here

For authenitication I am using windows. "Integrated Windows Authentication" is not checked. The current login user is me who is an Admin.
Lets narrowing the problem down to whether you are able to bind to AD in the first place

Dim objDE As New System.DirectoryServices.DirectoryEntry()
Dim ldapPath As String = "LDAP://<SERVER_NAME>/bla..bla.."
objDE.Path = Path
objDE.RefreshCache()

Try to run the above code and see what happen.
is it really objDE.Path = Path or what is path suppose to be?
oops..sorry..that should be
objDE.Path = ldapPath
okay the page simply reloaded.
Try more code and execute it

Dim objDE As New System.DirectoryServices.DirectoryEntry()
Dim ldapPath As String = "LDAP://<SERVER_NAME>/bla..bla.."
objDE.Path = Path
objDE.RefreshCache()
' check if this line gets executed with no error and please post the result
Dim ds As String = objDE.Properties("distinguishedName").Value

Dim objUser As  DirectoryServices.DirectoryEntry = objDE.children.Add("cn=" & login.text & "","user")
objUser.Properties("sAMAccountName").add(login.text)
objUser.Properties("sn").add(lname.text)
objUser.Properties("displayName").add(lname.text & "," & fname.text)
objUser.Properties("telephoneNumber").add(tel.text)
objUser.Properties("mail").add(email.text)
objUser.Properties("userAccountControl").add(512)
objUser.commitChanges()
that line didn't produce an error when the bottom part is left off. This code produces an error

UnauthorizedAccessException: General access denied error
]
   System.DirectoryServices.Interop.IAds.SetInfo() +0
   System.DirectoryServices.DirectoryEntry.CommitChanges() +37
   ASP.addaduser_aspx.add_ad(Object Source, EventArgs E) in D:\Intranet\Mystuff\Mystuff\addaduser.aspx:43
   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +108
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +57
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +18
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
   System.Web.UI.Page.ProcessRequestMain() +1277
hm..can you post the ldapPath value?
and the return value from this line
Dim ds As String = objDE.Properties("distinguishedName").Value
how do I get the return value for ds???
Here is the path

LDAP://CN=Users,DC=sthmpsn,DC=com
debugging by step through the code. Is your dev box is part of the AD domain? is the windows login account is member of domain administrator?
Yes and yes.

 I am using Dreamweaver for my coding so I have no idea how to debug to get you that value.
Use Response.Write( ds )
ds = CN=Users,DC=sthmpsn,DC=com

Try to include server name in the ldapPath, like this

Dim objDE As New System.DirectoryServices.DirectoryEntry()
Dim ldapPath As String = "LDAP://<SERVER_NAME>//CN=Users,DC=sthmpsn,DC=com"
objDE.Path = ldapPath
objDE.AuthenticationType = AuthenticationTypes.ServerBind
objDE.RefreshCache()
Dim ds As String = objDE.Properties("distinguishedName").Value

Dim objUser As  DirectoryServices.DirectoryEntry = objDE.children.Add("cn=" & login.text & "","user")
objUser.Properties("sAMAccountName").add(login.text)
objUser.Properties("sn").add(lname.text)
objUser.Properties("displayName").add(lname.text & "," & fname.text)
objUser.Properties("telephoneNumber").add(tel.text)
objUser.Properties("mail").add(email.text)
objUser.Properties("userAccountControl").add(512)
objUser.commitChanges()

And run the code
And do you have VS.NET installed on the dev machine? you might need to run the code on a console app to see whether security issues has something to do with this problem.
still the same
hm..forgot to ask. do you enable anonymous access in the IIS security settings?
no
Or pass the user name and password explicitly in your code

Dim objDE As New System.DirectoryServices.DirectoryEntry()
Dim ldapPath As String = "LDAP://<SERVER_NAME>//CN=Users,DC=sthmpsn,DC=com"
objDE.Username = "Domain/theUserAccount"
objDE.Username = "thePassword"
objDE.Path = ldapPath
objDE.AuthenticationType = AuthenticationTypes.ServerBind
objDE.RefreshCache()
...
...
[COMException (0x80072035): The server is unwilling to process the request.]
   System.DirectoryServices.Interop.IAds.SetInfo() +0
   System.DirectoryServices.DirectoryEntry.CommitChanges() +37
   ASP.addaduser_aspx.add_ad(Object Source, EventArgs E) in D:\Intranet\llctest\addaduser.aspx:44
   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +108
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +57
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +18
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
   System.Web.UI.Page.ProcessRequestMain() +1277
new error I just noticed
yup, commenting out this line
objUser.Properties("userAccountControl").add(512)
user shows up but account is disabled.
yup, but what is new created userAccountControl attribute value, by default 512 should be included automatically.
so what do I ned to do so that the user isn't disabled when he is created?
ASKER CERTIFIED SOLUTION
Avatar of ihenry
ihenry

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
The ADS_UF_ACCOUNTDISABLE is equal to 2

or you can just do this if no other settings required

objUser.Properties["userAccountControl"].Value = 512
objUser.commitChanges()
YES!!! Now two very short questions for you. How do you exchange enable the account? Also when you open AD and show the users what is the property name of the name that is displayed for each user. Like in ad my account is displayed under name as "Malloy, Nick", but when I am creating a user right now it displays the loginID as the name.
>> YES!!!
Is that means the user is created, enabled and with the correct password.

>> How do you exchange enable the account
Read this, but in c#
http://msdn.microsoft.com/library/en-us/sds/sds/enabling_and_disabling_the_user_account.asp

>> ..I am creating a user right now it displays the loginID as the name..
You mean via "Active Directory Users and Computers" snap-ins or ADSI viewer? "Active Directory Users and Computers" snap-ins should showing like "LastName, FirstName" and ADSI viewer is showing sAMAccountName value. I'm not very sure, though. I don't have access to AD now and far away from my office pc, but I let you know maybe tommorow.

Note:
Binding to AD is an expensive operation, thus closing and disposing connected DirectoryEntry object is necessary.
yes the user is created!!!! Now all I need to do is get it to display right under Active Directory Users and Computers and then enable exhange. I don't see in that link how you enable exchange. That looks like enabling an account.
sorry, understood it wrongly.

you mean, ms exchange?
yeah
First, You need to install CDOEXM in your dev machine. Import the necessary assembly to the project and read this article should put you on the right track.

http://support.microsoft.com/kb/313114

And be ready for another errors messages :o).

If you have problem just open another question, I'll try to help you as I can.
I've gotta sign off another few minutes. Good luck for you!
thanks for all your help
you're welcome!
Hi Nick, I still owed you one question

>> ...Like in ad my account is displayed under name as "Malloy, Nick",
>> but when I am creating a user right now it displays the loginID as the name.

When a user object is created in the “Active Directory Users and Computers” MMC, the names default as follows. You specify the “givenName”, “initials”, and “sn” attributes of the user and it's displayed as <givenName> <initials>. <sn>. The source of confusion is when you create a user programmatically it's displayed as cn attribute's value. You can overwrite this behaviour by set the cn attributes the same way as when you create a user via “Active Directory Users and Computers” MMC.