0

Ive created a Directory Searcher to pull multiple properties from each user.

objSearchADAM = new DirectorySearcher(objADAM);
objSearchADAM.PropertiesToLoad.Add("givenname");
objSearchADAM.PropertiesToLoad.Add("lastlogontimestamp");
ect...
objSearchResults = objSearchADAM.FindAll();

I then enumerate them, and convert the interger8 timestamp to standard date/time, and save to csv file with

 List<string> timeProps = new List<string>() { "lastlogontimestamp", "accountexpires", "pwdlastset", "lastlogoff", "lockouttime", "maxstorage", "usnchanged", "usncreated", "usndsalastobjremoved", "usnlastobjrem", "usnsource" };

            foreach (SearchResult objResult in objSearchResults)
            {
                objEntry = objResult.GetDirectoryEntry();


                ResultPropertyCollection myResultProp = objResult.Properties;
                foreach (string myKey in myResultProp.PropertyNames)
                {


                    foreach (Object myCollection in myResultProp[myKey])
                    {

                        Object sample = myCollection;


                        if (timeProps.Contains(myKey))
                        {
                            String times = sample.ToString();
                            long ft = Int64.Parse(times);
                            DateTime date;
                            try
                            {

                                date = DateTime.FromFileTime(ft);
                            }
                            catch (ArgumentOutOfRangeException ex)
                            {
                                date = DateTime.MinValue;
                                Console.WriteLine("Out of range: " + ft);
                                Console.WriteLine(ex.ToString());
                            }
                            sample = date;
                            Console.WriteLine("{0}{1}", myKey.PadRight(25), sample);
                            objWriter.WriteLine("{0}{1}", myKey.PadRight(25), sample);
                        }
                        else
                        {
                            Console.WriteLine("{0}{1}", myKey.PadRight(25), sample);
                            objWriter.WriteLine("{0}{1}", myKey.PadRight(25), sample);
                        }
                    }

now i need to create an object for each user with the strings from each result that i can put into an SQL command ive built. where the LDAP query to SQL would be givenname = FirstName and lastlogontimestamp = LastLogon and so on.

StringBuilder sb = new StringBuilder();
sb.Append("INSERT INTO activedirectory.dimUserST (FirstName, LastName) VALUES (@FirstName, @LastName)");
loadStagingCommand.Parameters.AddWithValue("@FirstName", FirstName).DbType =    DbType.AnsiString;
ect...
loadStagingCommand.CommandText = sb.ToString();
loadStagingCommand.ExecuteNonQuery();

i tried to use IDictionary in my first foreach (similar to code found here http://ideone.com/vChWD ) but couldn't get it to work. I read about IList and reflection, but im not sure how i could incorporate these.

UPDATE I researched and found ExpandoObjects and attempted to write in code based off of what i saw in here Creating Dynamic Objects however i run this new code I return "employeenumber System.Collections.Generic.List`1[System.Dynamic.ExpandoObject]"

if(employeeNumber.Contains(myKey))
                        {


                        string[] columnNames = { "EmployeeNumber" };
                        List<string[]> listOfUsers = new List<string[]>();
                        for (int i = 0; i < 10; i++)
                        {
                            listOfUsers.Add(new[] { myKey});
                        }

                        var testData = new List<ExpandoObject>();

                        foreach (string[] columnValue in listOfUsers)
                        {
                            dynamic data = new ExpandoObject();
                            for (int j = 0; j < columnNames.Count(); j++)
                            {
                                ((IDictionary<String, Object>)data).Add(columnNames[j], listOfUsers[j]);
                            }
                            testData.Add(data);
                          Console.WriteLine("{0}{1}", myKey.PadRight(25), testData);
                        objWriter.WriteLine("{0}{1}", myKey.PadRight(25), testData);
                        }

                        }

I am obviously missing something here and cant seem to wrap my head around what the problem is. I might even be going about this the wrong way. Basically all i need to do is pull users and their properties from Active Directory and put into SQL database tabels. And I've worked out how to do both separately, but I cant figure out how to put it all together.

2
  • Are you having problem retrieving the values from the property collection, or in creating the insert command? Commented Jun 18, 2013 at 21:00
  • I'm not able to retrieve the multiple values and keep them separate from each other and linked to the right user. Commented Jun 19, 2013 at 14:13

1 Answer 1

0

If the CSV is just being used to cache the results, you could use a Dictionary to store the contents of the search results instead. Separating your code into functions could be helpful:

private static object GetFirstValue(ResultPropertyCollection properties, 
                                       string propertyName)
{
    var propertyValues = properties[propertyName];
    var result = propertyValues.Count == 0 ? null : propertyValues[0];
    return result;
}

Then you could either use a dictionary to hold the property values, or you could create a type:

var results = new List<Dictionary<string, object>>();

foreach(SearchResult objResult in objSearchResults)
{
    var properties = objResult.Properties;

    var propertyDictionary = new Dictionary<string, object> { 
       {"FirstName", GetFirstValue(properties, "givenname")},
       {"LastName", GetFirstValue(properties, "sn")},
       {"UserName", GetFirstValue(properties, "samaccountname")},
    };

    results.Add(propertyDictionary);
}

Now you have a list of property bags.

This could also be a simple LINQ statement:

var results = objSearchResults.OfType<SearchResult>()
    .Select(s => s.Properties)
    .Select(p => new {
       FirstName = (string)GetFirstValue(properties, "givenname"),
       LastName = (string)GetFirstValue(properties, "sn"),
       UserName = (string)GetValue(properties, "samaccountname"),
       AccountExpires = GetDateTimeValue(properties, "accountexpires")
    });

Use the dictionaries like this:

foreach(var item in results)
{
    var command = new SqlCommand();
    ...
    command.Parameters.AddWithValue("firstName", item["FirstName"]);
    ...
}
Sign up to request clarification or add additional context in comments.

7 Comments

that seems like it might work, but it wont let me create the object GetFirstValue
To be sure I'll have to read it tomorrow when I'm at work. Something about it not being able to reach a path for variable?? Don't quote me
Sorry about that. I added a return statement to function.
It seems to be working fine, but now i just figure out why it is giving me results as System.Collections.Generic.Dictionary`2[System.String,System.Object]
That's just the shape of your cache. You're caching the properties into a dictionary because it's easy to extract them when you're ready to put them into your database. I'll add that to my answer.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.