Change Password For Win2000/ActiveDirectory Network with Visual C#

Hi,

Details: Windows 2000 Server, with Active Directory.

I'd like my VC# App' to change user-passwords on our network. I've looked into the NetUserChangePassword function and contrary to the documentation, it only seems to work for local users, rather than networked ones.  I've checked the syntax and documentation : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netuserchangepassword.asp ...

..and tried various versions of this:  

NetUserChangePassword("domain-or-server", "username", "oldpass", "newpass")
but it wont change (non-local) user password - it works fine for users on the local machine.

It also requires the current password, which is a shame as I'm an administrator user and obviously dont need to do that from the cmd prompt or via active directory.

So is it possible to change A Users Password - Without.. a) Needing to specify the current password b) Server (as we have lots of users on several servers)
Thanks.

- M
LVL 1
nikez2k4Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

mrichmonCommented:
You can never change a user password without knowing the current password.  What you are doing as an administrator is called setting the password, not changing it.

You always need to specify a server you are acting on.  But in active directory it will replicate across domain controllers so just specify the domain controller you are connecting to when you make the change.

As for how... I found this works for creating a user and setting a password (which it sounds like what you want to do):

(You can remove the creation of a user to change to searching for the user if you want)

// LDAP to connect to
static string LDAPpath = "LDAP://dc1.yourdomain.com/";

// OU container for all Users
static string myOU = "OU=Domain Users, DC=yourdomain, DC=com";

// UserName and password to connect to AD
static string username = @"yourdomain\manager";
static string password = @"Password";

DirectoryEntry de = new DirectoryEntry();

// Set credentials of an AD account to "Run As"
de.Username = username;
de.Password = password;

// Set active LDAP path to be the selected OU
de.Path = LDAPpath + myOU;

// Assign the users in the LDAPpath to a variable so we can manipulate it (add users)
DirectoryEntries users = de.Children;

// Add user account
DirectoryEntry user = users.Add("CN=" + LastName + "\\, " + FirstName + " [" + kerb + "]", "user");

// Set additional properties of new account
user.Properties["samAccountName"].Add(kerb); // Login name
user.Properties["givenName"].Add(FirstName); // First Name
user.Properties["sn"].Add(LastName); // Last Name

string userPassword = AddPassword.Text.Trim();

// Commit changes so far so we can then add additonal account properties
user.CommitChanges();

// SOme settings you may want:
// Set the account to be a "normal account" (0x10000) with "don't expire password" (0x200)
user.Properties["userAccountControl"].Value = ((int) user.Properties["userAccountControl"].Value) | 0x10200;
// Set the "account disable" to false (account disable = 0x2)
user.Properties["userAccountControl"].Value = ((int) user.Properties["userAccountControl"].Value) & ~0x2;

// Set Password
ActiveDs.IADsUser tempUser = (ActiveDs.IADsUser)user.NativeObject;
tempUser.ChangePassword("", userPassword);

// Commit password changes
user.CommitChanges();

Note that you must commit the initial changes for a account creation before the second commit of password changes actually work.  Otherwise you end up with a blank password regardless of what you set it to before the first commitchanges.
0
nikez2k4Author Commented:
Thanks for that.  I appreciate the difference between setting and changing, but how can I "set" the password for a pre-fined user (from a textbox, say) without having to compile the app with administrator credentials (as these may change) - Surely there must be a way to 'simulate' "net user password"?

- M
0
mrichmonCommented:
You have to have the application run with a windows account that has the credentials or you or can have the account to run as passed in from the form.
0
Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

nikez2k4Author Commented:
If I run the app' as an admin user (which would be the case) isn't there quite simply an alternative to this:
NetUserChangePassword("domain-or-server", "username", "oldpass", "newpass")
Which allows us to NOT need to supply the existing password?
Thanks.

0
nikez2k4Author Commented:
Even using the current password as required, is this syntax correct, as it doesnt work:

NetUserChangePassword("\\\\domain", "username", "current-pwd", "new-pwd");
0
mrichmonCommented:
I have never seen that syntax so I can't say that it will work.

As I mentioned before I spent months on this type of issue and found that even though there are supposedly many ways to do this, it turns out that the ways that actually work are very limited.  I gave an example of such above.

Instead of creating a user you could do a directory search and simply change the password on the user object resulting from the search.
0
nikez2k4Author Commented:
Thanks.  Must admit I can only understand portions of the code (I'm pretty new to this still) - but if I had already had the username (eg "Dave") or Textbox1.Text, or whatever - how can I put that into this:

-
ActiveDs.IADsUser tempUser = (ActiveDs.IADsUser)user.NativeObject;
tempUser.ChangePassword("", userPassword);
-
0
mrichmonCommented:
Well you have to use a directory searcher first to find the user based on the username.  Then you have the user object to work with.
0
nikez2k4Author Commented:
Yeah, okay - but I cant get that far yet as I cant even get it to work for a specific, predefined user -  I've trawled the net and found lots of similar examples - but none actually explain how it can be done on a user, or even array basis.   If I had a user "DOMAIN\SMITH", how can I set his password?
0
mrichmonCommented:
Here is code I have used to search for a specific user

using (DirectorySearcher searcher = new DirectorySearcher())
{
      searcher.SearchRoot = de;
      searcher.Filter = "(&(objectClass=user)(sAMAccountName=" + usernameToFind + "))";
      DirectoryEntry user = searcher.FindOne().GetDirectoryEntry();
}
0
mrichmonCommented:
Note some of the variables come from code higher up (like de is the directory entry in the previous code I posted)
0
nikez2k4Author Commented:
Obviously I'm pretty new to this, can you spell it out - what I need to put to get this working?
0
mrichmonCommented:
// LDAP to connect to
static string LDAPpath = "LDAP://dc1.yourdomain.com/";

// OU container for all Users
static string myOU = "OU=Domain Users, DC=yourdomain, DC=com";

// UserName and password to connect to AD
static string username = @"yourdomain\manager";
static string password = @"Password";

DirectoryEntry de = new DirectoryEntry();

// Set credentials of an AD account to "Run As"
de.Username = username;
de.Password = password;

// Set active LDAP path to be the selected OU
de.Path = LDAPpath + myOU;

using (DirectorySearcher searcher = new DirectorySearcher())
{
     searcher.SearchRoot = de;
     searcher.Filter = "(&(objectClass=user)(sAMAccountName=" + usernameToFind + "))";
     DirectoryEntry user = searcher.FindOne().GetDirectoryEntry();

     // Set Password
     ActiveDs.IADsUser tempUser = (ActiveDs.IADsUser)user.NativeObject;
     tempUser.ChangePassword("", userPassword);

     // Commit password changes
     user.CommitChanges();
}
0
nikez2k4Author Commented:
--
// Set credentials of an AD account to "Run As"
de.Username = username;
de.Password = password;
de.Path = LDAPpath + myOU;
--

Error      1      Invalid token '=' in class, struct, or interface member declaration      
(The "=" in line 1 above)
Error      1      Invalid token '=' in class, struct, or interface member declaration      
(The "=" in line 2 above)
Error      1      Invalid token '=' in class, struct, or interface member declaration      
(The "=" in line 3 above)
Error      1      Invalid token '=' in class, struct, or interface member declaration      
(The "+" in line 3 above)
Error      1      Invalid token '=' in class, struct, or interface member declaration      
(The ";" in line 3 above)
0
mrichmonCommented:
I don't know what you did to get the error. I use that exact code in several sites and it works.  It seems like you are missing something else that is causing these errors.
0
LaBCommented:
1. you're linking to a C++ article, thus NetUserChangePassword is a C++ function. I have never seen anything that resembles it in C#.

2. the errors you listed seem like you are using these declarations outside a method.
0
nikez2k4Author Commented:
Thx.  I'd like to be able to set/reset/change the password for users in a specifc group -- It's usually a small number of users (1-10max).  The users all live in the same domain but could exist on up to 4 different servers.
At the moment I've listed those users in a textbox but cant find any documentation on how to change their password.  As it happens, I would be able to specifcy their previous password but obviously I'd also be fine with resetting it as I have admin' priveldges on the network.
0
LaBCommented:
using System.DirectoryServices;

//
// These are the three values you must assign before running the code below.
//
string ServerName; // This is the DN of your domain: DC=XXXX,DC=YYYYY
string UserName; // The name of the user to change the password for.
string Password; //The new password for the user.

string errMsg;

DirectoryEntry myDirectoryEntry = new DirectoryEntry(String.Format("LDAP://{0}", ServerName));
DirectorySearcher search = new DirectorySearcher(myDirectoryEntry);
search.Filter = String.Format("(SAMAccountName={0})", UserName);
search.PropertiesToLoad.Add("SAMAccountName");
SearchResult result = search.FindOne();
if (result != null)
{
     myDirectoryEntry = result.GetDirectoryEntry();
     myDirectoryEntry.Invoke("setPassword", Password);
     myDirectoryEntry.CommitChanges();
}
else
{
     errMsg = String.Format("User, {0}, does not seem to exist", UserName);
}


of course, the user running this application must have sufficient rights on the domain, in order to change the password. Hope this helps.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
nikez2k4Author Commented:
*skips about* thats done it..  Just gotta sort out the iteration stuff.  That's a lot :-)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.