Sign in with
Sign up | Sign in
Your question
Solved

Active Directory C# help

Tags:
  • Programming
  • C#
  • Active Directory
  • Apps
Last response: in Apps General Discussion
Share
November 28, 2012 8:04:48 PM

Hello All,

Writting a new C# program to replace a very old VBS file. Pretty much the program will go through our AD and get all the users and their emails and put it in a CSV file. I found some basic code and ran it and I think it worked because I saw a huge list in the console but when it was finished it closed and gave me an error.

ERROR
System.ArgumentOutOfRangeException was unhandled
Message="Index was out of range. Must be non-negative and less than the size of the collection.\r\nParameter name: index"
Source="mscorlib"
ParamName="index"
StackTrace:
at System.Collections.ArrayList.get_Item(Int32 index)
at System.DirectoryServices.ResultPropertyValueCollection.get_Item(Int32 index)
at ConsoleApplication4.Program.Main(String[] args) in C:\Users\jsalina\Documents\Visual Studio 2008\Projects\ConsoleApplication4\ConsoleApplication4\Program.cs:line 26
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:


Code
  1. using System;
  2. using System.DirectoryServices;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6.  
  7. namespace ConsoleApplication4
  8. {
  9. class Program
  10. {
  11. static void Main(string[] args)
  12. {
  13. DirectoryEntry entry = new DirectoryEntry("LDAP://OU=PHF Users,DC=phf,DC=inc");
  14.  
  15. using (DirectorySearcher ds = new DirectorySearcher(entry))
  16. {
  17. ds.PropertiesToLoad.Add("name");
  18. ds.PropertiesToLoad.Add("userPrincipalName");
  19.  
  20. ds.Filter = "(&(objectClass=user))";
  21.  
  22. SearchResultCollection results = ds.FindAll();
  23.  
  24. foreach (SearchResult result in results)
  25. {
  26. Console.WriteLine("{0} - {1}",
  27. result.Properties["name"][0].ToString(),
  28. result.Properties["userPrincipalName"][0].ToString());
  29. }
  30. }
  31.  
  32. }
  33. }
  34. }


Any thoughts on it?


P.S. That just the basic code, trying to get it to work in the console before I add the CSV file and validations. Pretty new to this type of programming.

More about : active directory

a b L Programming
November 29, 2012 4:27:14 AM

What is happening basically is that result doesn't necessarily have properties "name" and "userPrincipalName". You should check whether it has that property first before accessing the first character of that property.
m
0
l
Related resources
November 29, 2012 12:15:49 PM

That is a good point Sunius, this was the the others guy who was teaching it names, I want to connect to the Ldp.exe and connect the the AD and get the exact names. Just new to this so want to ask boss to make sure I dont mess anything up in the company.

and majestic pretty new at this, All i know from college is basic c++ and java.
m
0
l
November 29, 2012 12:16:15 PM

That is a good point Sunius, this was the the others guy who was teaching it names, I want to connect to the Ldp.exe and connect the the AD and get the exact names. Just new to this so want to ask boss to make sure I dont mess anything up in the company.

and majestic pretty new at this, All i know from college is basic c++ and java.
m
0
l
November 29, 2012 12:50:05 PM

That's fine. Was just pointing out that I didn't have to do any custom LDAP parsing or building my own AD interaction objects. Just keep in mind that you'll only have permissions to do what the .Net machine account has rights to do within AD. I would strongly suggest you set up an account with which to impersonate for AD interaction even if it's a user with only read rights.
m
0
l
November 29, 2012 1:40:23 PM

Just got into the ldp and my names were wrong changed them but getting same errors between lines 26-28
m
0
l
November 29, 2012 3:09:58 PM

Here's the current code that is giving me an error. Just want it to work so I can move on and code the other things I need.

  1. using System;
  2. using System.DirectoryServices;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6.  
  7. namespace ConsoleApplication4
  8. {
  9. class Program
  10. {
  11. static void Main(string[] args)
  12. {
  13. DirectoryEntry entry = new DirectoryEntry("LDAP://OU=PHF Users,DC=phf,DC=inc");
  14.  
  15. using (DirectorySearcher ds = new DirectorySearcher(entry))
  16. {
  17. ds.PropertiesToLoad.Add("cn");
  18. ds.PropertiesToLoad.Add("mail");
  19.  
  20. ds.Filter = "(&(objectClass=user))";
  21.  
  22. SearchResultCollection results = ds.FindAll();
  23.  
  24. foreach (SearchResult result in results)
  25. {
  26. Console.WriteLine("{0} - {1}",
  27. result.Properties["cn"][0].ToString(),
  28. result.Properties["mail"][0].ToString());
  29. }
  30.  
  31. }
  32.  
  33.  
  34.  
  35. }
  36. }
  37. }
m
0
l
November 29, 2012 3:18:33 PM

Your problem is that you're assuming a state that isn't true by trying to go for the first element in the Properties collection when doing as you have done clearly doesn't have a first element. You can dig in and find out this info for yourself and I highly recommend it. Debug the result object to see what the Properties collection looks like and adjust your code accordingly.

If the Properties collection looks nothing like you'd expect then your premise about how that object works is wrong and you'll need to examine why.
m
0
l
November 29, 2012 3:44:42 PM

I am so confused, let me try to walk through the code and see if I understand it correctly.

1)We open PHF Users directory in the AD and set that path to entry.
2)We create a search of that directory using ds.
3)We then say we only want to Users Name and Email and set a filter to only grab Users
4)Then we set a search off all the data and put into results
5)Go through all the results only pulling out the CN and MAIL categories

Are you saying that the results are pulling every single category not just the CN and MAIL? (ie. accountExpires,badPasswordTime,badPwdCount......ect)
m
0
l
November 29, 2012 4:12:44 PM

I'm saying you're treating your 5th step in a way that's not meshing with how the results object actually works. You need to hook up a debugger and dig into the Properties collection to see how that object is being populated, if at all, and to adjust your code accordingly. Maybe the key name is different, maybe there is no element 0, etc. These are things that will become evident once you hook up a debugger.
m
0
l
November 29, 2012 4:38:01 PM

ok bare with me, I am pretty new at this debugging. Found the results and PropertiesLoaded and its saying its a string[3], [0]="cn" [1]="mail" and [2] ="ADsPath"(which idk what that is) Could this be the problem?
m
0
l
November 29, 2012 5:02:05 PM

If you put a quick watch on "result.Properties["cn"]" what are its members?
m
0
l
November 29, 2012 5:19:12 PM

so many collapsable menus, i went to:

result->Properties->PropertyName->non-public members->["cn"]->value->base->non-public members->list->non-public members->_items->
[0] "vault system"
[1] null
[2] null
[3] null

was that totally useless?
m
0
l
November 29, 2012 5:24:29 PM

when i hover over result.Properties["cn"][0].ToString(), the result says null on the little drop down, if it was working correctly I am guessing it would have a name in it right?
m
0
l
November 29, 2012 5:35:15 PM

Have you tried chopping off .ToString()?
m
0
l
November 29, 2012 6:07:10 PM

Ok I got rid of that other code and followed another coder on YouTube, his code seems to work, getting all the names, but when i try to add the mail component it errors, gonna work on in a little and ill be back
m
0
l
November 29, 2012 6:35:55 PM

  1. static void Main(string[] args)
  2. {
  3. var dc = new DirectoryContext(DirectoryContextType.Domain);
  4.  
  5. var d = Domain.GetDomain(dc);
  6.  
  7. var s = d.FindDomainController().GetDirectorySearcher();
  8.  
  9. s.Filter = "(&(objectClass=user))";
  10.  
  11. var f = s.FindOne();
  12.  
  13. Console.WriteLine(f.Path);
  14. Console.WriteLine(f.Properties["cn"][0]);
  15. Console.WriteLine(f.Properties["mail"][0]);
  16.  
  17. Console.ReadLine();
  18. }


This works fine for me. Perhaps try getting your searcher object using this method instead?
m
0
l
November 29, 2012 6:50:36 PM

what reference did u add to get directory context?
m
0
l
November 29, 2012 6:54:11 PM

System.DirectoryServices.ActiveDirectory
m
0
l
November 29, 2012 7:10:44 PM

Dont have that in my references =/
m
0
l
November 29, 2012 7:13:39 PM

So add it. As long as you ref to System.DirectoryServices you can declare using System.DirectoryServices.ActiveDirectory.
m
0
l
November 29, 2012 7:25:21 PM

the mail is still give me that same error
m
0
l
November 29, 2012 7:31:30 PM

Are you sure that property exists in that domain? As in can you go to a domain controller, open up AD and view a user to see its mail entry?
m
0
l
November 29, 2012 7:31:51 PM

I got my other code running find for user names, need to just get the mail working adn exporting the info to a CSV file, my next steps
m
0
l
November 29, 2012 7:33:39 PM

Yup, have the ldp open and looking at a user and they have a mail: xxxxxxx@xxxxx.org
m
0
l
November 29, 2012 7:41:50 PM

Well, it showed up earlier when you spit out the results of Properties. What if you drill into it like you did with cn?
m
0
l
November 29, 2012 7:44:04 PM

it not even just mail, any 2nd object i try to pull same error, only seems cn works
m
0
l
November 29, 2012 7:44:38 PM

heres the new code btw

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.DirectoryServices;
  5. using Microsoft.Office.Interop.Excel;
  6. using System.DirectoryServices.ActiveDirectory;
  7.  
  8.  
  9. namespace EmailListing
  10. {
  11. class Program
  12. {
  13. static void Main(string[] args)
  14. {
  15.  
  16.  
  17. DirectoryEntry adFolderObject = new DirectoryEntry("LDAP://OU=PHF Users,DC=phf,DC=inc");
  18.  
  19. DirectorySearcher adSearchObject = new DirectorySearcher(adFolderObject);
  20.  
  21. adSearchObject.SearchScope = SearchScope.Subtree;
  22.  
  23. adSearchObject.Filter = "(&(ObjectClass=user)(!description=Built-in*))";
  24.  
  25. foreach (SearchResult adObject in adSearchObject.FindAll())
  26. {
  27. Console.WriteLine("cn={0}", adObject.Properties["cn"][0]);
  28. // Console.WriteLine("co={0}", adObject.Properties["co"][0]);
  29.  
  30. }
  31.  
  32. Console.WriteLine();
  33. Console.ReadLine();
  34. }
  35. }
  36. }
m
0
l

Best solution

November 29, 2012 7:56:33 PM

Did you try digging into name like you did with cn? Also, double check what permissions are setup as AD may not be sending that info as you may not be allowed to see anything except names.
Share
November 29, 2012 8:02:04 PM

well done, i dug into it and its only bringing in 32 fields and mail isnt one of them. Now how do we get all the fields brought in lol
m
0
l
November 29, 2012 8:08:00 PM

You'll need to research that one. Google is your friend.
m
0
l
November 30, 2012 3:53:42 PM

I found stuff on active direct schema, do I need to add a new using class for it? some of the schema options arent showing up
m
0
l
November 30, 2012 4:35:10 PM

That's beyond my expertise, mate.
m
0
l
November 30, 2012 5:01:24 PM

alright thanks a lot for everything else
m
0
l
November 30, 2012 6:44:47 PM

Best answer selected by laserpp.
m
0
l
!