We had a script in Powershell where we manipulated the Active Directory. I programmed it now in C#. My collegues say that they had to specify the domain controller in PS because otherwise it can happen that you read with DC A and write on DC B which could cause problems.
Do I really have to specify the Domain Controller if I'm using DirectorySearcher to find an entry and manipulate it? Or does per definition the same Domain Controller is user for finding the object (DirectorySearcher) and saving it (CommitChanges)?
I do not think so, since I can only specify it in the searching part (DirectoryEntry object for the DirectorySearcher) but not when it is written back to the AD (CommitChanges). So I suppose that the same DC is used for writing like the one used for reading.
Below I have an example where I search for a specific entry and change a property.
string filter = "(proxyaddresses=SMTP:johndoe#abc.com)";
string searchOU = "ou=Users,dc=abc,dc=com";
DirectoryEntry entry = new DirectoryEntry("LDAP://" + searchOU);
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = filter;
SearchResult result = search.FindOne();
search.Dispose();
entry.Close();
DirectoryEntry toContact = result.GetDirectoryEntry();
toContact.Properties["showInAddressBook"].Value = addressbook;
toContact.CommitChanges();
toContect.Close();
Might I recommend using the objects available in the System.DirectoryServices.AccountManagement namespace? It's a more recent addition to .NET and handles AD work much more gracefully. It's recently saved me a whole lot of heartache which the older DirectorySearcher way of doing things was in part causing. Let the framework take the strain! There are lots of really useful articles around on the web, such as here.
As an example of how to use PrincipalContext for searching Active directory, try this:
var adContext = new PrincipalContext(ContextType.Domain);
var queryTemplateUser = new UserPrincipal(adContext);
queryTemplateUser.SamAccountName = "HenryCrunn";
var ldapSearcher = new PrincipalSearcher(queryTemplateUser);
var searchResults = ldapSearcher.FindAll();
Related
Trying to find who joined the computer to the domain. But in C# (.NET Core).
This is the exact answer (the question title is not worded well):
Powershell ADSI ntSecurityDescriptor
$Computer = [ADSI](([ADSISearcher]"(name=myComputer)").FindOne().Path)
$Computer.PsBase.ObjectSecurity.Owner
Alternatively, you can do this, but you need to have the Active Directory Module installed:
(Get-ADComputer myComputer -Server some.domain.com -Properties nTSecurityDescriptor).nTSecurityDescriptor.Owner
My assumption is that this returns who joined the computer to the domain, but I don't know how this actually works. However this seems like the data I need, but I want to do this in C#.
This is what I've figured out based on StephenP's answer from that Powershell ADSI ntSecurityDescriptor question
string ldapPath = "LDAP://DC=some,DC=domain,DC=com";
DirectoryEntry searchRoot = new DirectoryEntry(ldapPath);
DirectorySearcher search = new DirectorySearcher(searchRoot)
{
SearchScope = SearchScope.Subtree,
Filter = "(&" +
"(objectClass=computer)" +
"(CN=machineName)"
")"
};
var result = search.FindOne();
// if GetOwner doesn't return null, then it will contain the SID (call .Value)
result.GetDirectoryEntry().ObjectSecurity.GetOwner(typeof(System.Security.Principal.NTAccount));
//this will translate the SID to a domain\username format, but will throw IdentityNotMappedException if it can't translate
result.GetDirectoryEntry().ObjectSecurity.GetOwner(typeof(System.Security.Principal.SecurityIdentifier));
Hope this works in your AD environment as well...
Straight to the point, I have a request for a new project on which I have to find the primary and secondary owners for a specific list of Active Directory groups. When I get the array of secondary owners for each group, each of the owners are identified by their "distinguishedName" which led me to use a snippet like this to get the owner's info:
using (DirectoryEntry entry = new DirectoryEntry("LDAP://" + distinguishedName))
{
using (DirectorySearcher dSearch = new DirectorySearcher(entry))
{
SearchResult found = dSearch.FindOne();
if (found != null)
{
using (DirectoryEntry userEntry = found.GetDirectoryEntry())
{
Console.WriteLine("Username: " + userEntry.Properties["namefield"].Value + " : " + userEntry.Properties["emailfield"].Value);
}
}
else
{
Console.WriteLine("User not found with distinguishedName: " + distinguishedName);
}
}
}
GC.Collect();
I am a little concerned by the performance of this task since I have to get this information at the page loading sequence to check if the logged user is an owner or not. I have other AD browsing task to do and I've been doing some research on best practices with C# and AD and haven't found anything helpful yet so I though that you guys could provide some input on this.
Thanks for all your help.
f you have distinguished name of an object, you can bind to the object directly. Searching with DirectorySearcher is an excessive operation. Just create DirectoryEntry object and call its RefreshCache method. The fastest performance in ad is provided by classes located under System.DirectoryServices.Protocols namespace. Also one more optimization can be done: at the start of your program create a DirectoryEntry object and bind, e. g. To rootdse. This will establish ldap connection under the hood. All other queries will use this ldap connection. Keep the object alive until the program finishes
Credit to: oldovets
I'm currently creating an application which is using outlook as well as the exchange server / active directory in my company to create mails (I've had a few other questions here thus already).
I'm currently trying to read the GAL for it to be used when sending mails over my application. From the solutions I've seen so far it seems to me that the variant where I read the mail addresses from the active directory instead of connecting to the exchange server (I first tried outlook but aside from getting only the account names with the type "EX" thus that they are stored on the exchange server I didn't get much info there).
What I've done so far is gtting access to teh active directory and reading all users from there
DirectorySearcher objsearch = new DirectorySearcher();
String strrootdse = objsearch.SearchRoot.Path;
DirectoryEntry objdirentry = new DirectoryEntry(strrootdse);
objsearch.Filter = "(& (mailnickname=*)(objectClass=user))";
objsearch.SearchScope = System.DirectoryServices.SearchScope.Subtree;
objsearch.PropertiesToLoad.Add("cn");
objsearch.PropertiesToLoad.Add("mail");
objsearch.PropertyNamesOnly = true;
objsearch.Sort.Direction = System.DirectoryServices.SortDirection.Ascending;
objsearch.Sort.PropertyName = "cn";
SearchResultCollection colresults = objsearch.FindAll();
List<String> arrGal = new List<String>();
foreach (SearchResult objresult in colresults)
{
arrGal.Add(objresult.GetDirectoryEntry().Properties["cn"].Value + ": " + objresult.GetDirectoryEntry().Properties["mail"].Value);
}
Now after looking at the active directory I saw that there are also proxies and that (at least at my company) the "mail" property is not necessarily one of the mail addresses listed in the proxies.
Thus I found these two attributes: msExchShadowProxyAddresses, proxyAddresses
From what I've seen so far from them by looking at samples they look like they are identical, but even searching I didn't find anything on the web so far there.
Thus my Question when I'm trying to get the GAL from active directory Can I use both of these properties (thus they are always identical) or should I only use the ShadowProxy property or is there something I need to take into special consideration there?
You need to use AddressEntry.GetExchangeuser method. See my reply to your other post.
I need to create desktop shortcuts to my app for all administratos in the system.
I'm using the following code to get user list.
var identifier = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
GroupPrincipal group = GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Machine), identifier.Value);
foreach (Principal principal in group.Members)
{
Console.WriteLine(principal.Name);
}
I need somehow to get desktop path for each user. Could you suggest me solution? Many thanks.
You'll want to pinvoke the SHGetFolderLocation function (http://msdn.microsoft.com/en-us/library/bb762180.aspx) which allows you to pass in an access token that represents the user you're interested in.
No idea how difficult that will be though.
There are a few options that you can go with, depending on how you want to do it.
Option A:
Hard coded, but it works for default system setups
var userDirectory = Path.Combine("C:\Users\", principal.Name, "\Desktop");
Option B:
Find for the current user, then swap it out
var currentUser = Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
var newUser = currentUser.Replace("MyUser", principal.Name);
Now, option B hasn't been fully tested, but should work!
Each of our users is assigned to a primary organizational unit (OU) based on which global office they are in. So the "Chicago" OU contains all the associates in our Chicago office.
Using c# and .net 3.5, my task is to extract all of these users.
Unless the users are in a satellite or home office, their street address, city, state, etc. are empty, but the OU contains these details. When in Windows' Active Directory interface, right clicking on the OU and selecting properties gives a place to put all of this information just as on a user. However, when I try to access these properties like I do a user, I get an object reference error, suggesting these attributes do not exist the same way for an OU that they do for a user.
How do/can I access these location parameters from an OU object?
Here is a sample of the code I am using, showing streetaddress as an example, the statement trying to assign the value of streetaddress from the OU fails, where the assignment from associate succeeds.
foreach (SearchResult subOU in results)
{
ResultPropertyValueCollection subColl = subOU.Properties["distinguishedname"];
string subPath = subColl[0].ToString();
DirectoryEntry subEntry = new DirectoryEntry("LDAP://" + subPath);
DirectorySearcher userSearcher = new DirectorySearcher(subEntry);
userSearcher.SearchScope = SearchScope.OneLevel;
userSearcher.Filter = "(objectClass=user)";
foreach (SearchResult user in userSearcher.FindAll())
{
ResultPropertyValueCollection userColl = user.Properties["distinguishedname"];
string userPath = userColl[0].ToString();
DirectoryEntry userEntry = new DirectoryEntry("LDAP://" + userPath);
PropertyCollection associateProperties = userEntry.Properties;
PropertyCollection ouProperties = subEntry.Properties;
string streetAddress = string.Empty;
if (associateProperties["streetaddress"].Value == null)
{ streetAddress = ouProperties["streetaddress"].Value.ToString(); }
else
{ streetAddress = associateProperties["streetaddress"].Value.ToString(); }
}
}
If you change the Street-field on the General-tab in Active Directory Users & Computers for a user the value is stored in the streetAddress-attribute in the directory. If however you change the same field for an OU that value is stored in the street-attribute of that OU in the directory.
This is because OU objects are not (as defined in the Active Directory default schema) permitted to contain the streetAddress-attribute.
So (not having analyzed your code further) if you change ouProperties["streetaddress"] to ouProperties["street"] you'll might get the result you're looking for.
To avoid the ObjectReference exception you should check the collection contains the required attribute using the Contains(string) method. See here
I believe that AD will only stored valued attributes on an object, if a particular attribute has never been assigned a value it won't be available.
I found the AD schema references at:
http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-ADA1%5D.pdf A-L
http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-ADA2%5D.pdf Just M
http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-ADA3%5D.pdf N-Z
http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-ADTS%5D.pdf AD technical info
That would answer this question for you.
Also, the Win2K8 ADUC MMC snapin if you go to View, select Advanced Features, (enable the tick) then you get the Attribute Editor. (Something ConsoleOne for eDirectory has had for probably close to a decade now!).
One small note, in AD schema, first character is always lower case, and I run at sufficiently high res that the lower case L's are hard to see as L's. (Need a better screen font, but mea culpa).