Tuesday, July 17, 2007

The Code is Killing Me

And now I want it to kill you... Okay I don't want it to kill you.

This is a neat bit of code, I had to create a new local user in Windows XP. Then I had to change two things, I had to add it to the administrator's group and flag it so that the user's password never expires. As you may or may not know the local users and computers on Windows XP is very similar to Active Directory (I still owe you the Authenticate through AD post). However, there are enough differences that all the AD code I found was just the vaguest of hints as to what I needed to do.

You obviously have to use this in Windows form mode. I'll post a screen shot of the form and then the code.


Sorry I've forgotten all the sites and searches I did.



Now for the Code


The formatting (I hope) will be okay. However I don't think you'll be getting colours. If anyone reads this and knows of a program I can use to convert code to html with formatting and colours I would love an e-mail.

Form



Code Behind

namespace AddLocalUser
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void BtnOK_Click(object sender, EventArgs e)
{
if (TxtUserName.Text.Length > 0 && TxtPassword.Text.Length > 0)
{
if (TxtPassword.Text.Equals(TxtConfirmPassword.Text))
{
try
{
DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName +_ ",computer");
DirectoryEntry NewUser = AD.Children.Add(TxtUserName.Text, "user");
NewUser.Invoke("SetPassword", new object[] { TxtPassword.Text });
NewUser.Invoke("Put", new object[] { "Description", "Computer owner" });

//Insert the User.
NewUser.CommitChanges();
//Now change the "UserFlags" so that the password never expires
int iUserAccountControl = (int)ADS_USER_FLAG.ADS_UF_DONT_EXPIRE_PASSWD;
NewUser.Properties["UserFlags"].Value = iUserAccountControl;
NewUser.CommitChanges();
DirectoryEntry grp;

grp = AD.Children.Find("Administrators", "group");
if (grp != null) { grp.Invoke("Add", new object[] { NewUser.Path.ToString() }); }

}
catch(Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
else
{
LblMessage.Visible = true;
LblMessage.Text = "The Password fields must match";
LblMessage.ForeColor = System.Drawing.Color.Red;
}
}
else
{
LblMessage.Visible = true;
LblMessage.Text = "All fields must be filled out";
LblMessage.ForeColor = System.Drawing.Color.Red;
}
}


(BAH Sorry about the formatting I tried really hard..okay sorta hard)


Explanation


This is an easy bit of code to write. I'll go through it real quick.
DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName +_ ",computer");
DirectoryEntry NewUser = AD.Children.Add(TxtUserName.Text, "user");
NewUser.Invoke("SetPassword", new object[] { TxtPassword.Text });
NewUser.Invoke("Put", new object[] { "Description", "Computer owner" });

//Insert the User.
NewUser.CommitChanges();
This bit is pretty similar (If I'm not mistaken) to the AD version of adding a user. The big difference is using "Environment.MachineName" instead of using your AD server address.

Two DirectoryEntries are used, one for the Directory on your computer. One for the user that you are adding. The CommitChanges() slaps it into the local directory.

//Now change the "UserFlags" so that the password never expires
int iUserAccountControl = (int)ADS_USER_FLAG.ADS_UF_DONT_EXPIRE_PASSWD;
NewUser.Properties["UserFlags"].Value = iUserAccountControl;
NewUser.CommitChanges();
DirectoryEntry grp;

grp = AD.Children.Find("Administrators", "group");
if (grp != null) { grp.Invoke("Add", new object[] { NewUser.Path.ToString() }); }
This is the more interesting part. This changes the user options that we wanted to change. The ADS_USER_FLAG is obtained by referencing ActiveDS, and then of course adding "using ActiveDs;" to the top of your form code.

Your NewUser Directory entry is used again here. Change the .Property["UserFlags"] to the UserControl int you declare above. Here is a big change from AD code, in Active Directory you would use NewUser.Properties[attribute name]. Here we are changing the UserFlags instead.

After that we create a new Directory entry that will represent the group we want to add the user to. "Find" the group we are looking for (Administrators) and then check to see if that group came back to our object correctly. If it did, simply invoke the add function from AD and point it at the path of our NewUser DirectoryEntry.


WOW I hope that made sense, I did not enjoy writing that i must say. I will try to edit it before I post but my brain may liquefy before I finish that.

Have fun Everyone

This comes in in all sizes