Hello Everyone i am trying to develop a program that will list will all the user of Active Directory and when i select one user the program should be able to show the computers associated with that user. i.e the Computers that are accessible to that AD user.
I have written code to list all user but no idea how to list the computers associated with that user.
Here is my code to load AD User into datatable:
DataTable dtUser= new DataTable();
try
{
DirectoryEntry dom = Domain.GetComputerDomain().GetDirectoryEntry();
DirectorySearcher dsAllUsers = new DirectorySearcher(dom);
dsAllUsers.SearchScope = SearchScope.Subtree;
dsAllUsers.Filter = "(objectCategory=Person)";
SearchResultCollection result = dsAllUsers.FindAll();
dtUser.Columns.Add("CustodianName");
dtUser.Columns.Add("Email");
dtUser.Columns.Add("Title");
dtUser.Columns.Add("Dept.");
foreach (SearchResult rs in result)
{
DataRow newRow = dtUser.NewRow();
if (rs.GetDirectoryEntry().Properties["samaccountname"].Value != null)
newRow["CustodianName"] = rs.GetDirectoryEntry().Properties["samaccountname"].Value.ToString();
if (rs.GetDirectoryEntry().Properties["mail"].Value != null)
newRow["Email"] = rs.GetDirectoryEntry().Properties["mail"].Value.ToString();
if (rs.GetDirectoryEntry().Properties["title"].Value != null)
newRow["Title"] = rs.GetDirectoryEntry().Properties["title"].Value.ToString();
if (rs.GetDirectoryEntry().Properties["department"].Value != null)
newRow["Dept."] = rs.GetDirectoryEntry().Properties["department"].Value.ToString();
dtUser.Rows.Add(newRow);
}
return dtUser;
}
catch (Exception)
{
throw;
}
I don't believe standard LDAP/Active Directory has anything like this.
Computers are just another class of AD objects - but there's no "link" between a user and one (or multiple) computer(s) - there's no belongsTo attribute on the computer class, nor is there a computers collection on User.
If your organization has implemented an extension to the default AD schema (which is entirely possible!), it's a custom solution, and then you must know what it is! :-)
Related
I have an In-house C# application that will be run on lap-tops in several remote locations. The most common users will have admin rights to the lap-tops, but sometimes it will be run by users without admin rights. For operational reasons, we want just one copy of the application per computer, so it will be installed under Program Files instead of the user accounts.
I am creating an auto-update routine. I would like it to have this behavior:
It checks if there are any updates available.
If there are updates and the user has no admin rights, They will be informed of the updates.
If the user has admin rights, the updates will be loaded.
In all cases, the application will be launched. Non-admin users can decide if the updates warrant shutting down and finding someone with admin rights.
99% of the time, there will be no updates, and I would prefer not to request privileges in the manifest when they usually will not be needed. So I plan on starting a separate process to actually load the updates. But in that case, I'd rather not bother non-admin users with requests for admin privileges that they cannot provide (no - they will not have another account they themselves can log into that has admin privileges).
Is there some reliable way I can have it determine - once it has found updates - whether the current user is in the administrators group, so that it will know whether to bother with launching the update process, or just report updates available and move on?
I've been searching for hours, but have only turned up one method (checking if the user has a split token) that is apparently unreliable and warned against.
Edit:
For completeness, the final solution I found based on Wheels73's post with corrections for the error I was getting is:
bool CurrentUserIsAdmin()
{
UserPrincipal user = UserPrincipal.Current;
using (IEnumerator<Principal> groups = user.GetAuthorizationGroups().GetEnumerator())
{
while (groups.MoveNext())
{
try
{
if (groups.Current.ToString() == "Administrators")
{
return true;
}
}
catch (NoMatchingPrincipalException)
{
continue;
}
}
return false;
}
}
As discussed, this is the routine I use to list all the AD directories for a given login.
public List<string> GetUsersActiveDirectoryGroups(string windowsUserName)
{
var allUserGroups = new List<string>();
var domainConnection = new DirectoryEntry();
var samSearcher = new DirectorySearcher
{
SearchRoot = domainConnection,
Filter = "(samAccountName=" + windowsUserName + ")"
};
samSearcher.PropertiesToLoad.Add("displayName");
var samResult = samSearcher.FindOne();
if (samResult == null) //User not found
return allUserGroups;
//Get groups
var theUser = samResult.GetDirectoryEntry();
theUser.RefreshCache(new[] {"tokenGroups"});
foreach (byte[] resultBytes in theUser.Properties["tokenGroups"])
{
var mySid = new SecurityIdentifier(resultBytes, 0);
var sidSearcher = new DirectorySearcher
{
SearchRoot = domainConnection,
Filter = "(objectSid=" + mySid.Value + ")"
};
sidSearcher.PropertiesToLoad.Add("name");
var sidResult = sidSearcher.FindOne();
if (sidResult != null)
{
allUserGroups.Add(sidResult.Properties["name"][0].ToString());
}
}
return allUserGroups;
}
You could then check the contents of the groups to return a bool based upon the group name you are looking for.
var myUsersGroups = GetUsersActiveDirectoryGroups("YOURLOGINNAME");
var usersIsInAdmin = myUsersGroups.Any(g => g == "Administrator");
To detect if a user simply has loca admin rights, you can use the below
WindowsIdentity user = null;
user = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(user);
var isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
OK.. final shout :)
To find out if another user has local admin rights, you can do the below
var usersPrincipal = UserPrincipal.FindByIdentity(UserPrincipal.Current.Context, IdentityType.SamAccountName, "YOURLOGINNAME");
var otherUserIsAdmin = usersPrincipal.GetAuthorizationGroups().Any(p => p.ToString() == "Administrators");
Hope that helps.
I wrote a small app to check AD group members. When I execute the following code on my pc, It works well, the SearchResult contains the "member" property, however when I run the same exe on the server or on an another computer the "member" property is missing. The usnchanged and usncreated will be different also. I run the exe with the same user on every pc. What can cause this?
...
using (DirectorySearcher searcher = new DirectorySearcher())
{
searcher.CacheResults = false;
searcher.Filter = "(&(objectClass=group)(cn=" + ADName + "))";
searcher.SizeLimit = int.MaxValue;
searcher.PageSize = int.MaxValue;
if (!DirectoryEntry.Exists(ADPath))
{
return null;
}
searcher.SearchRoot = new DirectoryEntry(ADPath);
using (SearchResultCollection collection = searcher.FindAll())
{
if (collection.Count == 1)
{
return collection[0];
}
}
}
...
The group membership data is not replicated to the global catalog. The query might work sometimes, if you happen to connect to the domain controller with the actual membership data. On other machines, you probably connect to other domain controllers, of different domains, where the information is not available.
You might want to connect to a domain controller in the actual domain, not to the global catalog.
I'm currently working on a project where i have to pull some Active Directory information on all our servers.
The thing is i ONLY wan't the servers in AD, and not all the desktop computers.
The servers are located in multiple sub directories, for each location.
I was able to filter on operating system like this, but as some of them are cluster servers AD havn't picked up the OS of the ones hosted on those so I need to create a filter or some logic that only looks in the OU's called Servers.
This is what i currently have:
DirectoryEntry entry = new DirectoryEntry(path);
// Create a DirectorySearcher object.
DirectorySearcher mySearcher = new DirectorySearcher(entry);
// Set a filter for users with the name test.
// Search specific computer replace OperatingSystem=Windows*Server* with anr=<servername>
mySearcher.Filter = "(&(objectClass=computer)(OperatingSystem=Windows*Server*))";
mySearcher.SearchScope = SearchScope.Subtree;
results = mySearcher.FindAll();
mySearcher.PropertiesToLoad.Add("cn");
mySearcher.PropertiesToLoad.Add("dnshostname");
mySearcher.PropertiesToLoad.Add("Site");
mySearcher.PropertiesToLoad.Add("Description");
mySearcher.PropertiesToLoad.Add("Location");
mySearcher.PropertiesToLoad.Add("operatingsystem");
mySearcher.PropertiesToLoad.Add("operatingsystemservicepack");
mySearcher.PropertiesToLoad.Add("operatingsystemversion");
mySearcher.PropertiesToLoad.Add("managedBy");
con.Open();
foreach (SearchResult searchResult in results)
{
cmd.Parameters.AddWithValue("#Servername", Convert.ToString(searchResult.GetDirectoryEntry().Properties["cn"].Value));
cmd.Parameters.AddWithValue("#DNSHostname", Convert.ToString(searchResult.GetDirectoryEntry().Properties["dnshostname"].Value));
cmd.Parameters.AddWithValue("#Description", Convert.ToString(searchResult.GetDirectoryEntry().Properties["description"].Value));
cmd.Parameters.AddWithValue("#Site", Convert.ToString(searchResult.GetDirectoryEntry().Properties["Site"].Value));
cmd.Parameters.AddWithValue("#Location", Convert.ToString(searchResult.GetDirectoryEntry().Properties["Location"].Value));
cmd.Parameters.AddWithValue("#OS", Convert.ToString(searchResult.GetDirectoryEntry().Properties["operatingsystem"].Value));
cmd.Parameters.AddWithValue("#OSServicePack", Convert.ToString(searchResult.GetDirectoryEntry().Properties["operatingsystemservicepack"].Value));
cmd.Parameters.AddWithValue("#OSVersion", Convert.ToString(searchResult.GetDirectoryEntry().Properties["operatingsystemversion"].Value));
cmd.Parameters.AddWithValue("#ManagedBy", Convert.ToString(searchResult.GetDirectoryEntry().Properties["managedBy"].Value));
if (searchResult.Path.Contains("OU=Test") == true)
{
cmd.Parameters.AddWithValue("#IsTestServer", 1);
}
else
{
cmd.Parameters.AddWithValue("#IsTestServer", 0);
}
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
}
After some more search today i found the solution here on the website
get computer from OU
Hello I'm stuck trying to add a function to my Windows forms program that allows a user to type in a textbox what computer or computers they would like to search for in Active Directory. The user would input the search string in a textbox then hit a button and the computers that match that search result would appear in a separate search box. Here is my code so far.
I would also like each computer name to be on a separate line such as:
computername1
computername2
computername3
Thanks!
This is what inside the button looks like:
List<string> hosts = new List<string>();
DirectoryEntry de = new DirectoryEntry();
de.Path = "LDAP://servername";
try
{
string adser = txtAd.Text; //textbox user inputs computer to search for
DirectorySearcher ser = new DirectorySearcher(de);
ser.Filter = "(&(ObjectCategory=computer)(cn=" + adser + "))";
ser.PropertiesToLoad.Add("name");
SearchResultCollection results = ser.FindAll();
foreach (SearchResult res in results)
//"CN=SGSVG007DC"
{
string computername = res.GetDirectoryEntry().Properties["Name"].Value.ToString();
hosts.Add(computername);
//string[] temp = res.Path.Split(','); //temp[0] would contain the computer name ex: cn=computerName,..
//string adcomp = (temp[0].Substring(10));
//txtcomputers.Text = adcomp.ToString();
}
txtcomputers.Text = hosts.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
de.Dispose();//Clean up resources
}
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on the System.DirectoryServices.AccountManagement namespace
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find a computer
ComputerPrincipal computer = ComputerPrincipal.FindByIdentity(ctx, "SomeComputerName");
if (computer != null)
{
// do something here....
}
}
If you don't need to find a single computer, but search for a whole list of computers, you can use the new PrincipalSearcher interface, which basically allows you to set up a "QBE" (query-by-example) object you're looking for, defining the search criteria, and then search for matches for those criteria.
The new S.DS.AM namespace makes it really easy to play around with users and groups in AD!
I have the following method used for searching for a User Group either on the local computer (done first) or in the Current Forest.
public string FindUserGroup(string group)
{
//Search local computer
using (DirectorySearcher searcher = new DirectorySearcher(new DirectoryEntry()))
{
searcher.Filter = "(&(objectClass=group)(|(cn=" + group + ")(dn=" + group + ")))";
SearchResult result = searcher.FindOne();
if (result != null)
return TranslateDirectoryEntryPath(result.GetDirectoryEntry().Path);
}
//Search current forest
Forest forest = Forest.GetCurrentForest();
foreach (Domain domain1 in forest.Domains)
{
using (DirectorySearcher searcher = new DirectorySearcher(domain1.GetDirectoryEntry()))
{
searcher.Filter = "(&(objectClass=group)(|(cn=" + group + ")(dn=" + group + ")))";
SearchResult result = searcher.FindOne();
if (result != null)
return TranslateDirectoryEntryPath(result.GetDirectoryEntry().Path);
}
}
return string.Empty;
}
My problem is that we as an example have say "domain.local" and "mydomain.local", and my current login is bound to "domain.local", then using below won't be able to find anything in "mydomain.local", even if I through the Windows User Interface is able to.
How can I search all viewable providers from my computers perspective when I don't nessesarily know them all? Do I REALLY have to do the Registry Work my self?
Edit:
One difference in the 2 domains is the "level" they are on when I in an object browser dialog chooses "Locations", it layouts as:
Computer
Entire Direction
domain.local
mydomain.local
So "mydomain.local" excists outside what is referred to as "Entire Directory", yet my computer can locate it, if that makes any difference?
I don't see a problem as this code here would have already be binded to the other domains.
foreach (Domain domain1 in forest.Domains)
{
using (DirectorySearcher searcher = new DirectorySearcher(domain1.GetDirectoryEntry()))
{
Are you trying to say that later on you're binding a DirectoryEntry on your own, and you can't find objects from other domain?