Ahmed
Ahmed

Reputation: 11403

How to programmatically create Windows user accounts on Windows 7 or Windows Server 2008?

I've been trying to create new local user accounts on windows 7 machine. I used the System.DirectoryServices.DirectoryEntry class (as in here) but it doesn't seem to work.

Here's the code in the article:

static void Main(string[] args)
{
try
    {
 DirectoryEntry AD = new DirectoryEntry("WinNT://" + 
                     Environment.MachineName + ",computer");
 DirectoryEntry NewUser = AD.Children.Add("TestUser1", "user");
 NewUser.Invoke("SetPassword", new object[] {"#12345Abc"});
 NewUser.Invoke("Put", new object[] {"Description", "Test User from .NET"});
 NewUser.CommitChanges();
 DirectoryEntry grp;

 grp = AD.Children.Find("Guests", "group");
 if (grp != null) {grp.Invoke("Add", new object[] {NewUser.Path.ToString()});}
 Console.WriteLine("Account Created Successfully");
 Console.ReadLine();
}
catch (Exception ex)
{
 Console.WriteLine(ex.Message);
 Console.ReadLine();

}
}

When executing this line

DirectoryEntry NewUser = AD.Children.Add("TestUser1", "user");

I get a

System.Runtime.InteropServices.COMException with "{"Unknown error (0x80005000)"}"

as the exception message, and -2147463168 as the error code.

I assume this is probably because the article targets Windows XP and below machines, and I'm targeting windows 7 and Windows server 2008.

Any help appreciated!

Update:
For some mysterious reason, i'm no longer seeing that System.Runtime.InteropServices.COMException, however, when committing the changes here newuser.CommitChanges(), I get a "UnAuthorizedAccessException". I tried running the app as administrator, but still not working.

Update 2:
OK, after changing to the UserPrincipal class, i got the follwoing code to work:

public UserPrincipal CreateNewUser(string sUserName, string sPassword)
        {
            // first check that the user doesn't exist
            if (GetUser(sUserName) == null)
            {
                PrincipalContext oPrincipalContext = GetPrincipalContext();

                UserPrincipal oUserPrincipal = new UserPrincipal(oPrincipalContext);
                oUserPrincipal.Name = sUserName;
                oUserPrincipal.SetPassword(sPassword);
                //User Log on Name
                //oUserPrincipal.UserPrincipalName = sUserName;
                oUserPrincipal.Save();

                return oUserPrincipal;
            }

            // if it already exists, return the old user
            return GetUser(sUserName);
        }
    }


This code runs well when I run it as a console app -of course run as administrator- but when i deployed it as a windows service, with the security account set as "LocalSystem", i get an InvlaidOperationException saying "The underlying store does not support this property"

Thoughts?

Upvotes: 7

Views: 26726

Answers (2)

Ahmed
Ahmed

Reputation: 11403

OK, if you check my last update, the following snippet worked:

public UserPrincipal CreateNewUser(string sUserName, string sPassword)
        {
            // first check that the user doesn't exist
            if (GetUser(sUserName) == null)
            {
                PrincipalContext oPrincipalContext = GetPrincipalContext();

                UserPrincipal oUserPrincipal = new UserPrincipal(oPrincipalContext);
                oUserPrincipal.Name = sUserName;
                oUserPrincipal.SetPassword(sPassword);
                //User Log on Name
                //oUserPrincipal.UserPrincipalName = sUserName;
                oUserPrincipal.Save();

                return oUserPrincipal;
            }

            // if it already exists, return the old user
            return GetUser(sUserName);
        }
    }

That worked as a console app, but failed to execute due to security exceptions when deployed as a windows service. A solution is to trust that assembly (the windows service assembly) so that the .net security will let it run. That's done, now everything is cool!

Upvotes: 9

Warren Rumak
Warren Rumak

Reputation: 3874

You need to prefix your username with CN=, like so:

DirectoryEntry NewUser = AD.Children.Add("CN=TestUser1", "user");

Upvotes: 0

Related Questions