C#, why I can't add domain user into local group? - c#

Why this code doesn work ? What I want to do is add domain user into local group.
DirectorySearcher srch = new DirectorySearcher(new DirectoryEntry("LDAP://" + "AD1.test.it/DC=test,DC=it"));
srch.Filter = "(&(objectClass=user)(sAMAccountName=testUser))";
SearchResultCollection results = srch.FindAll();
DirectoryEntry de = new DirectoryEntry(results[0].Path);
DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName);
DirectoryEntry dComUsersGrp = localMachine.Children.Find("Distributed COM Users", "group");
dComUsersGrp.Invoke("Add", new object[] { de.Path.ToString() });
I get this error: "Exception has been thrown by the target of an invocation."
Simillar code works for adding local user into a local group.
DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName);
DirectoryEntry de = localMachine.Children.Find("testUser", "user");
DirectoryEntry dComUsersGrp = localMachine.Children.Find("Distributed COM Users", "group");
dComUsersGrp.Invoke("Add", new object[] { de.Path.ToString() });
Thank you very much for any help.

string userPath = string.Format("WinNT://{0}/{1},user", domain, user);
string groupPath = string.Format("WinNT://{0}/{1},group", Environment.MachineName, group);
using (DirectoryEntry group = new DirectoryEntry(groupPath))
{
group.Invoke("Add", userPath);
group.CommitChanges();
}
You need to use WinNT:// ADSI namespace.

You usually have to specify logon credentials to access the directory. Something like:
String domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);

Related

How can I retrieve the phone number from Active Directory using User Principal Context

This code works perfectly to get the phone number from Active Directory using the username and password
public string GetPhone(string domain, string username, string pwd)
{
_path = "LDAP://" + domain;
string domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
string telephoneNumber = string.Empty;
try
{
object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
SearchResult result = search.FindOne();
var myEntry = result.GetDirectoryEntry();
telephoneNumber = myEntry.Properties["telephoneNumber"].Value.ToString();
}
catch (Exception ex)
{
throw new Exception("Error obtaining phone number. " + ex.Message);
}
return telephoneNumber;
}
However, I have access to the user password only on the login page. I do have the User context being generated though that is accessible from anywhere within the application (Context.User which is of System.Security.Principal.IPrincipal type)
Thus, how can I get the phone from Active Directory using an already available Context.User object?
Thank you very much in advance
The User object you get will have the SID of the user. With that, you can use the SID binding LDAP path in DirectoryEntry: LDAP://<SID=XXXXX>
var user = new DirectoryEntry(
$"LDAP://<SID={((WindowsIdentity) HttpContext.User.Identity).User.Value}>");
user.RefreshCache(new [] { "telephoneNumber" });
var telephoneNumber = user.Properties["telephoneNumber"]?.Value as string;
The use of RefreshCache is to load only the telephoneNumber attribute. Otherwise, when you first use .Properties, it will retrieve every attribute, which is a waste of time and bandwidth.
Looks like I overcomplicated everything and solution is quite simple
private void SetPhone()
{
DirectoryEntry entryDomain = new DirectoryEntry("LDAP://" + domain);
DirectorySearcher ds = new DirectorySearcher(entryDomain);
string lastName = Context.User.Identity.Name.Split(' ')[Context.User.Identity.Name.Split(' ').Length - 1];
ds.Filter = "(sn=" + lastName + ")";
SearchResult sr = ds.FindOne();
string telephoneNumber = sr.Properties["telephoneNumber"][0].ToString();
telephoneNumber = telephoneNumber.Insert(0, "(").Insert(4, ")").Insert(5, " ").Insert(9, "-");
Session["UserPhone"] = String.Format("{0:(###) ###-####}", telephoneNumber); ;
}

Query Active Directory using DistinguishedName

I have an application that uses Windows authentication and I am trying to get logged in users info using their domain IDs.
Part of the data returned is the user's manager's DN (in manager property). I need to query AD again to get manager's info (domain id, email, name, etc.).
I searched and can't find any hint of what I have to use in my filter.
This is what I am using and I always get null returned:
private static DirectoryEntry GetUserDEByDN(string sDN)
{
using (HostingEnvironment.Impersonate())
{
PrincipalContext pc = new PrincipalContext(ContextType.Domain, adUSADomain, adUSAContainer);
//UserPrincipal up = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, UserID);
UserPrincipal qbeUser = new UserPrincipal(pc);
//qbeUser.SamAccountName = UserID.Trim().ToUpper();
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
PrincipalSearchResult<Principal> psr = srch.FindAll();
string sDomain = ConfigurationManager.AppSettings["Domain"].ToString();
string adPath = ConfigurationManager.AppSettings["ADPath"].ToString();
DirectoryEntry de = new DirectoryEntry(adPath);
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = de;
deSearch.Filter = "(&(objectClass=user)(| (cn = " + sDN + ")(dn = " + sDN + ")))";
//deSearch.Filter = "(&(objectClass=user)(SAMAccountName=" + UserID + "))";
deSearch.SearchScope = SearchScope.Subtree;
SearchResult results = deSearch.FindOne();
if (null != results)
{
de = new DirectoryEntry(results.Path);
return de;
}
else
{
return null;
}
}
}
Is it possible to search Active Directory by DN? If so, what I am doing wrong?
This is what worked for me. However, I believe it is supposed to work with objectClass=user but I kept getting null returned. When I changed to distinguishedName = sDN, it worked.
The whole point of this code
DirectoryEntry de = new DirectoryEntry(adPath + "/" + sDN);
is to start the directory search at the user object; there shouldn’t be the need for the additional search of saying which distinguishedName.
private static DirectoryEntry GetUserDEByDN(string sDN)
{
string adPath = ConfigurationManager.AppSettings["ADPath"].ToString();
DirectoryEntry de = new DirectoryEntry(adPath + "/" + sDN);
DirectoryEntry deManager = null;
using (DirectorySearcher Search = new DirectorySearcher())
{
Search.SearchRoot = de;
Search.Filter = "(&(distinguishedName=" + sDN + "))";
//Search.Filter = "(objectClass = user)";
Search.SearchScope = SearchScope.Base;
SearchResult Result = Search.FindOne();
if (null != Result)
deManager = Result.GetDirectoryEntry();
}
return deManager;
}

Accessing the LDAP with PrincipalContext to a public server

I am having issues connecting to a public LDAP using PrincipalContext. I can get directory entry working fine:
string sDomain = "LDAP://ldap.itd.umich.edu:389";
string sDefaultOU = "ou=System Groups,ou=Groups,dc=umich,dc=edu";
string sServiceUser = "cn=Directory Manager,o=University of Michigan,c=us";
string sServicePassword = "";
DirectoryEntry de = new DirectoryEntry(sDomain + "/" + sDefaultOU, sServiceUser, sServicePassword, AuthenticationTypes.ServerBind);
DirectorySearcher ds = new DirectorySearcher(de);
SearchResult sr = ds.FindOne();
But when I try to do the same thing with PrincipalContext I get a null reference error:
sDomain = "ldap.itd.umich.edu";
PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Domain, sDomain, sDefaultOU, sServiceUser, "");
Any ideas what I am doing wrong?

Permissions required for adding an Active Directory account through code

I'm attempting to write a program that would automatically create active directory accounts using data from an external data source. The problem that I am running into is that I am always getting an UnAuthorizedAccessException but I for the life of me can't think of what permissions to apply. I've even gone all the way to the root object and given my own account full control which doesn't seem to make any difference. I know that I can access the server since the organizationUnit and de objects are populated correctly.
DirectoryEntry de = new DirectoryEntry("LDAP://MYLOCALADDRESS");
de.Password = "thePassword";
de.Username = "theUserName";
de.AuthenticationType = AuthenticationTypes.Secure ;
DirectoryEntry organizationalUnit = de.Parent;
DirectoryEntry newUser = organizationalUnit.Children.Add("TESTADD ", de.SchemaClassName);
//Exception happens on this line
newUser.CommitChanges();
Any help would be appreciated!
At a glance I'd say your "TESTADD " needs to start with "CN="
For active directory I get all my samples from this codeproject:
public string CreateUserAccount(string ldapPath, string userName,
string userPassword)
{
try
{
string oGUID = string.Empty;
string connectionPrefix = "LDAP://" + ldapPath;
DirectoryEntry dirEntry = new DirectoryEntry(connectionPrefix);
DirectoryEntry newUser = dirEntry.Children.Add
("CN=" + userName, "user");
newUser.Properties["samAccountName"].Value = userName;
newUser.CommitChanges();
oGUID = newUser.Guid.ToString();
newUser.Invoke("SetPassword", new object[] { userPassword });
newUser.CommitChanges();
dirEntry.Close();
newUser.Close();
}
catch (System.DirectoryServices.DirectoryServicesCOMException E)
{
//DoSomethingwith --> E.Message.ToString();
}
return oGUID;
}

get computer from OU

I have a code to get a list of all the computers within a domain.
Now i need to just get the computers which are within a particular OU and not the rest of the machines.
so here is my code to get all the machines from a domain, this works perfectly fine:
DirectoryEntry entry = new DirectoryEntry("LDAP://" + selectDomain);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = ("(objectClass=computer)");
mySearcher.SizeLimit = int.MaxValue;
mySearcher.PageSize = int.MaxValue;
foreach (SearchResult resEnt in mySearcher.FindAll())
{
//"CN=SGSVG007DC"
string ComputerName = resEnt.GetDirectoryEntry().Name;
if (ComputerName.StartsWith("CN="))
ComputerName = ComputerName.Remove(0, "CN=".Length);
compList.Add(ComputerName);
}
mySearcher.Dispose();
entry.Dispose();
any suggestions?? thanks.
You just need to add the OU to your directory entry, so instead of taking the root of your domain as being the search path, it takes the domain + OU as being the search path.
See "Enumerating objects in an OU" # http://www.codeproject.com/KB/system/everythingInAD.aspx
I see from your commments that you're having issues here, so let's put this simply - note that this code isn't tested, but should clarify...
string selectDomain = "CN=myCompany,CN=com";
string selectOU = "OU=LosAngeles,OU=America";
DirectoryEntry entry = new DirectoryEntry("LDAP://" + selectOU + "," + selectDomain);
That essentially gives you the string of "LDAP://OU=LosAngeles,OU=America,CN=MyCompany,CN=com" as the new directory entry. You must specify the full LDAP path, not just the OU or the domain.
try to use this Directory entry:
DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://OU={0},{1}", ouName, selectDomain));
i tried all the above.. but it did not work... so this is what i tried and it worked.
i understand this is not the best way but its the only way working for me... any suggestion.. thanks
DirectoryEntry entry = new DirectoryEntry("LDAP://" + selectedDomain);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = ("(objectClass=organizationalUnit)");
mySearcher.SizeLimit = int.MaxValue;
mySearcher.PageSize = int.MaxValue;
foreach (SearchResult temp in mySearcher.FindAll())
{
Global.logger.Debug("OU = " + temp.Properties["name"][0].ToString());
DirectoryEntry ou = temp.GetDirectoryEntry();
DirectorySearcher mySearcher1 = new DirectorySearcher(ou);
mySearcher1.Filter = ("(objectClass=computer)");
mySearcher1.SizeLimit = int.MaxValue;
mySearcher1.PageSize = int.MaxValue;
if (temp.Properties["name"][0].ToString() == selectedOU)
{
foreach (SearchResult resEnt in mySearcher1.FindAll())
{
//"CN=SGSVG007DC"
string ComputerName = resEnt.GetDirectoryEntry().Name;
Global.logger.Debug("ComputerName = " + resEnt.Properties["name"][0].ToString());
if (ComputerName.StartsWith("CN="))
ComputerName = ComputerName.Remove(0, "CN=".Length);
compList.Add(ComputerName);
}
}
mySearcher1.Dispose();
ou.Dispose();
}
mySearcher.Dispose();
entry.Dispose();

Categories

Resources