Will this code work with an NT domain?

P

Peter Steele

I have code to add a domain user to a local group but I'm not sure if it
will work with NT domains or whether it will only work with Active Directory
based systems. Here's the code:

public void AddDomainUserToLocalGroup(string computerName, string groupName,
string domainName, string userName)
{
Hashtable htRet = new Hashtable();
IADsContainer groupComputer = (IADsContainer)Win32.GetObject("WinNT://"
+ computerName + ",computer");
IADsGroup group = (IADsGroup)groupComputer.GetObject("group",
groupName);
group.Add("WinNT://" + domainName + "/" + userName);
}
 
N

Nicholas Paldino [.NET/C# MVP]

Peter,

On domains where there is not an AD controller, the call to GetObject
will return nothing, so it will not work.

Hope this helps.
 
P

Peter Steele

Is there a generic implementation of this that would work with both NT and
AD domains? I assume there must be an underlying Win32 API call I could
make?

Peter

Nicholas Paldino said:
Peter,

On domains where there is not an AD controller, the call to GetObject
will return nothing, so it will not work.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Peter Steele said:
I have code to add a domain user to a local group but I'm not sure if it
will work with NT domains or whether it will only work with Active
Directory based systems. Here's the code:

public void AddDomainUserToLocalGroup(string computerName, string
groupName, string domainName, string userName)
{
Hashtable htRet = new Hashtable();
IADsContainer groupComputer =
(IADsContainer)Win32.GetObject("WinNT://" + computerName + ",computer");
IADsGroup group = (IADsGroup)groupComputer.GetObject("group",
groupName);
group.Add("WinNT://" + domainName + "/" + userName);
}
 
W

Willy Denoyette [MVP]

Peter Steele said:
Is there a generic implementation of this that would work with both NT and
AD domains? I assume there must be an underlying Win32 API call I could
make?
Yep, here's a sample...

using System.DirectoryServices;
.....

private static void AddToGroup(string groupName)
{
// Domain administrator account as a sample...
string userPath = "WinNT://DCName/Administrator,User";
DirectoryEntry userEntry = new DirectoryEntry(userPath,
"domainadmin","hispwd", AuthenticationTypes.ServerBind);
object o = userEntry.NativeObject;
if (o == null)
{
Console.WriteLine("No such account");
return;
}

using(DirectoryEntry container = new
DirectoryEntry("WinNT://localMachineName","localadmin", "hispwd",
AuthenticationTypes.ServerBind))
{
DirectoryEntry groupEntry = container.Children.Find(groupName, "group");
object newEntry = groupEntry.Invoke("add",
new object[] {userEntry.Path} );
groupEntry.CommitChanges();
}
}

public static void Main() {
// Add domain Administrator to Guests
AddToGroup("Guests");
}

Willy.
 
P

Peter Steele

Thanks for this code, I'll have to give it a try. Is there similar technique
for creating a domain account using DirectoryServices? I basically want to
do something like NetUserAdd to add user X to domain Y and there is a
possibility that the workstation where I am running the code will not be in
the domain.

Willy Denoyette said:
Peter Steele said:
Is there a generic implementation of this that would work with both NT
and AD domains? I assume there must be an underlying Win32 API call I
could make?
Yep, here's a sample...

using System.DirectoryServices;
....

private static void AddToGroup(string groupName)
{
// Domain administrator account as a sample...
string userPath = "WinNT://DCName/Administrator,User";
DirectoryEntry userEntry = new DirectoryEntry(userPath,
"domainadmin","hispwd", AuthenticationTypes.ServerBind);
object o = userEntry.NativeObject;
if (o == null)
{
Console.WriteLine("No such account");
return;
}

using(DirectoryEntry container = new
DirectoryEntry("WinNT://localMachineName","localadmin", "hispwd",
AuthenticationTypes.ServerBind))
{
DirectoryEntry groupEntry = container.Children.Find(groupName, "group");
object newEntry = groupEntry.Invoke("add",
new object[] {userEntry.Path} );
groupEntry.CommitChanges();
}
}

public static void Main() {
// Add domain Administrator to Guests
AddToGroup("Guests");
}

Willy.
 
W

Willy Denoyette [MVP]

Peter Steele said:
Thanks for this code, I'll have to give it a try. Is there similar
technique for creating a domain account using DirectoryServices? I
basically want to do something like NetUserAdd to add user X to domain Y
and there is a possibility that the workstation where I am running the
code will not be in the domain.
Sure, check this
http://msdn.microsoft.com/library/d...n-us/sds/sds/binding_to_directory_objects.asp

Note that most of the samples in
http://msdn.microsoft.com/library/en-us/sds/sds/quick_list_for_c__code_examples.asp?
are for AD domain management using the LDAP provider interface, NT4 domains
only support a limitted subset of the AD properties and the semantics and
syntax can differ significantly, check MSDN for differences.

To get you started, here's a sample that creates a local account in the
Guest alias.

using System.DirectoryServices;
using System.Runtime.InteropServices;
using System;
class AdsiUser
{
// User flags used to set user properties see AdSI doc's in MSDN
const int UF_SCRIPT = 0x0001;
const int UF_ACCOUNTDISABLE = 0x0002;
const int UF_HOMEDIR_REQUIRED = 0x0008;
const int UF_LOCKOUT = 0x0010;
const int UF_PASSWD_NOTREQD = 0x0020;
const int UF_PASSWD_CANT_CHANGE = 0x0040;
const int UF_TEMP_DUPLICATE_ACCOUNT = 0x0100;
const int UF_NORMAL_ACCOUNT = 0x0200;
const int UF_DONT_EXPIRE_PASSWD = 0x10000;
const int UF_PASSWORD_EXPIRED = 0x800000;
public static void Main()
{
string userName = "Tester";
DirectoryEntry NewUser;
//Bind and get the local computer container object using WinNT provider
// Use LDAP as provider to bind against an AD domain
using(DirectoryEntry computer = new DirectoryEntry("WinNT://" +
Environment.MachineName + ",computer", ".\\Administrator", "kevin"))
{
// delete user when existing
NewUser = computer.Children.Find(userName, "User");
if (NewUser != null)
computer.Children.Remove(NewUser);

// Add entry using the user schema
NewUser = computer.Children.Add(userName, "user");
NewUser.Properties["fullname"].Add("Tester account");
NewUser.Properties["description"].Add("test user acount");
NewUser.Properties["PasswordExpired"].Add(1); // user must change
password at next login
// Set some user flags
// this flag is different when binding to computer domain using LDAP
NewUser.Properties["userFlags"].Add(UF_NORMAL_ACCOUNT
|UF_DONT_EXPIRE_PASSWD
);
// invoke native method 'SetPassword' before commiting
// for computer domain accounts this must be done after commiting
NewUser.Invoke("SetPassword", new Object[] {"#12345Abc"});
NewUser.CommitChanges();
foreach(string s in NewUser.Properties.PropertyNames)
Console.WriteLine(s + " " + (NewUser.Properties)[0]);

// Add user to guests alias
DirectoryEntry grp = computer.Children.Find("guests", "group");
try {
if (grp.Name != null)
grp.Invoke("Add", new Object[] {NewUser.Path.ToString()});
Console.WriteLine("Account Created Successfully");
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
}
}
}


Willy.
 
P

Peter Steele

Thanks much!

Peter

Willy Denoyette said:
Peter Steele said:
Thanks for this code, I'll have to give it a try. Is there similar
technique for creating a domain account using DirectoryServices? I
basically want to do something like NetUserAdd to add user X to domain Y
and there is a possibility that the workstation where I am running the
code will not be in the domain.
Sure, check this
http://msdn.microsoft.com/library/d...n-us/sds/sds/binding_to_directory_objects.asp

Note that most of the samples in
http://msdn.microsoft.com/library/en-us/sds/sds/quick_list_for_c__code_examples.asp?
are for AD domain management using the LDAP provider interface, NT4
domains only support a limitted subset of the AD properties and the
semantics and syntax can differ significantly, check MSDN for differences.

To get you started, here's a sample that creates a local account in the
Guest alias.

using System.DirectoryServices;
using System.Runtime.InteropServices;
using System;
class AdsiUser
{
// User flags used to set user properties see AdSI doc's in MSDN
const int UF_SCRIPT = 0x0001;
const int UF_ACCOUNTDISABLE = 0x0002;
const int UF_HOMEDIR_REQUIRED = 0x0008;
const int UF_LOCKOUT = 0x0010;
const int UF_PASSWD_NOTREQD = 0x0020;
const int UF_PASSWD_CANT_CHANGE = 0x0040;
const int UF_TEMP_DUPLICATE_ACCOUNT = 0x0100;
const int UF_NORMAL_ACCOUNT = 0x0200;
const int UF_DONT_EXPIRE_PASSWD = 0x10000;
const int UF_PASSWORD_EXPIRED = 0x800000;
public static void Main()
{
string userName = "Tester";
DirectoryEntry NewUser;
//Bind and get the local computer container object using WinNT provider
// Use LDAP as provider to bind against an AD domain
using(DirectoryEntry computer = new DirectoryEntry("WinNT://" +
Environment.MachineName + ",computer", ".\\Administrator", "kevin"))
{
// delete user when existing
NewUser = computer.Children.Find(userName, "User");
if (NewUser != null)
computer.Children.Remove(NewUser);

// Add entry using the user schema
NewUser = computer.Children.Add(userName, "user");
NewUser.Properties["fullname"].Add("Tester account");
NewUser.Properties["description"].Add("test user acount");
NewUser.Properties["PasswordExpired"].Add(1); // user must change
password at next login
// Set some user flags
// this flag is different when binding to computer domain using LDAP
NewUser.Properties["userFlags"].Add(UF_NORMAL_ACCOUNT
|UF_DONT_EXPIRE_PASSWD
);
// invoke native method 'SetPassword' before commiting
// for computer domain accounts this must be done after commiting
NewUser.Invoke("SetPassword", new Object[] {"#12345Abc"});
NewUser.CommitChanges();
foreach(string s in NewUser.Properties.PropertyNames)
Console.WriteLine(s + " " + (NewUser.Properties)[0]);

// Add user to guests alias
DirectoryEntry grp = computer.Children.Find("guests", "group");
try {
if (grp.Name != null)
grp.Invoke("Add", new Object[] {NewUser.Path.ToString()});
Console.WriteLine("Account Created Successfully");
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
}
}
}


Willy.
 
P

Peter Steele

One thing I've noticed in your code is that you make explicit reference to
the domain controller:

"WinNT://DCName/Administrator,User"

In my original version the code doesn't need to know this information. All
it needs to know is the name of the domain, not the DC servicing the domain.
Is there a way around this or should I plan on passing it as a parameter?

Willy Denoyette said:
Peter Steele said:
Is there a generic implementation of this that would work with both NT
and AD domains? I assume there must be an underlying Win32 API call I
could make?
Yep, here's a sample...

using System.DirectoryServices;
....

private static void AddToGroup(string groupName)
{
// Domain administrator account as a sample...
string userPath = "WinNT://DCName/Administrator,User";
DirectoryEntry userEntry = new DirectoryEntry(userPath,
"domainadmin","hispwd", AuthenticationTypes.ServerBind);
object o = userEntry.NativeObject;
if (o == null)
{
Console.WriteLine("No such account");
return;
}

using(DirectoryEntry container = new
DirectoryEntry("WinNT://localMachineName","localadmin", "hispwd",
AuthenticationTypes.ServerBind))
{
DirectoryEntry groupEntry = container.Children.Find(groupName, "group");
object newEntry = groupEntry.Invoke("add",
new object[] {userEntry.Path} );
groupEntry.CommitChanges();
}
}

public static void Main() {
// Add domain Administrator to Guests
AddToGroup("Guests");
}

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top