Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert PropertyValueCollection into List C# ? ( ResultPropertyCollection , SearchResult , LDAP)

I've fired a query to read some stuff from Active Directory. But the result has some kind of "ResultPropertyCollection" as property. Any body knows How Can I convert it to a list ( like Generic List) ?

DirectoryEntry de = new DirectoryEntry("LDAP://" + this.rootLDAP);
    DirectorySearcher ds = new DirectorySearcher(de, "(& (objectcategory=Group))");

    ds.PropertiesToLoad.Add("samaccountname");
    ds.PropertiesToLoad.Add("memberof");
    ds.PropertiesToLoad.Add("samaccounttype");
    ds.PropertiesToLoad.Add("grouptype");
    ds.PropertiesToLoad.Add("member");
    ds.PropertiesToLoad.Add("objectcategory");

     var r = ( from SearchResult sr in ds.FindAll() select sr ) .ToArray();

Thanks Farzad

like image 844
Farzad J Avatar asked Nov 14 '11 11:11

Farzad J


2 Answers

You can't - at least not very easily.

If you want to just simply have a list of SearchResult types, you could use:

var r = ds.FindAll();

List<SearchResult> results = new List<SearchResult>();

foreach (SearchResult sr in r)
{
   results.Add(sr);
}

But if you want the actual values from the search results, you need to do more work.

Basically, that collection contains all the properties you've defined for the search - at least as long as they contain a value!

So really, what you need to do is create a class to hold those values. The two elements are memberOf and member can themselves contain multiple values (they're "multi-valued" attributes in AD) - so you'll need a list of strings for these:

public class YourType
{
    public string SamAccountName { get; set; }
    public int SamAccountType { get; set; }
    public int GroupType { get; set; }
    public string ObjectCategory { get; set; }
    public List<string> MemberOf { get; set; }
    public List<string> Member { get; set; }
}

Then, once you have your search result, you need to iterate over the results and create new instances of YourType for each search result, and stick those into a List<YourType>:

foreach(SearchResult sr in ds.FindAll())
{
    YourType newRecord = ConvertToYourType(sr);
}

and in that method, you need to inspect the .Properties collection for each value and extract it:

public YourType ConvertToYourType(SearchResult result)
{
    YourType returnValue = new YourType();
    returnValue.MemberOf = new List<string>();
    returnValue.Member = new List<string>();

    if(result.Properties["samAccountName"] != null && result.Properties["samAccountName"].Count > 0)
    {
       returnValue.SamAccountName = result.Properties["samAccountName"][0].ToString();
    }

    // ..... and so on for each of your values you need to extracxt

    return returnValue;
}
like image 172
marc_s Avatar answered Sep 21 '22 17:09

marc_s


I was also confused at first, but it was all matter of getting the type of the property collection item. Once I found out that the type of the properties item is System.Collections.DictionaryEntry and that the value is a collection made out of ResultPropertyValueCollection items, simple iterations were possible.

Here is what I ended up with:

        bool attemptResult = false;
        string ldap = "LDAP:<Your A.D. specific connection string>";
        DirectoryEntry entry = new DirectoryEntry(ldap, username, password, AuthenticationTypes.Secure);

        try
        {
            DirectorySearcher searcher = new DirectorySearcher(entry);
            searcher.Filter = "(&(objectClass=User)(sAMAccountName=" + username + "))";
            SearchResult one = searcher.FindOne();
            attemptResult = true;
            string properties = "";
            string userData = JsonConvert.SerializeObject(one.Properties);
            foreach (System.Collections.DictionaryEntry de in one.Properties) {
                properties += (properties.Length > 0 ? ",\n" : "");
                properties += "\"" + de.Key + "\": [";
                ResultPropertyValueCollection vc = ((ResultPropertyValueCollection)de.Value);
                foreach (var val in vc) {
                    properties += "{\"type\": \"" + val.GetType().Name + "\", \"value\"; \"" + val.ToString() + "\"}";
                }
                properties += "]";
            }
            properties = properties.Replace("}{", "},{");

            string displayName = one.Properties["displayname"][0].ToString();
            string givenName = one.Properties["givenname"][0].ToString();
            string lastname =  one.Properties["sn"][0].ToString();
        }
        catch (Exception e) {
            //log the error;
        }            
        return attemptResult;

Notice the fast and easy conversion to string using JsonConvert.SerializeObject. This a one step conversion.

I also performed a personalized conversion to string by using foreach iterations. This was more a self-teaching exercise from wich I get that after I get the value for a named property, I can find out whether the properties has zero, one or more values and act accordingly, even validating the object type if it were necessary.

Here is the value obtained in both string variables, properties and userData (Some items removed for privacy).

/* Value of userData Obtained with Json serializator*/

{"givenname":["First Name"],"samaccountname":["User.Name"],"cn":["First Name Last Name"],"pwdlastset":[131641282827115142],"whencreated":["2017-10-12T22:16:43"],"badpwdcount":[0],"displayname":["First Name Last Name"],"lastlogon":[131648243091569908],"samaccounttype":[805306368],"countrycode":[0],"objectguid":["SOMETHINGBASE64LIKE=="],"usnchanged":[52144153],"manager":["CN=The Name Of A Person,OU=Department Name,OU=City,OU=GroupName ,DC=Domain,DC=com"],"whenchanged":["2018-03-02T23:21:54"],"name":["First Name Last Name"],"objectsid":["SOMETHINGBASE64LIKE=="],"lastlogoff":[0],"lockouttime":[0],"badpasswordtime":[131647632246625185],"instancetype":[4],"primarygroupid":[513],"objectcategory":["CN=Person,CN=Schema,CN=Configuration,DC=Domain,DC=com"],"logoncount":[1073],"useraccountcontrol":[512],"description":["Some text"],"dscorepropagationdata":["1601-01-01T00:00:00"],"distinguishedname":["CN=First Name Last Name,OU=Department Name,OU=City,OU=GroupName ,DC=Domain,DC=com"],"objectclass":["top","person","organizationalPerson","user"],"adspath":["LDAP://Server/CN=First Name Last Name,OU=Department Name,OU=City,OU=GroupName ,DC=Domain,DC=com"],"usncreated":[39705915],"lastlogontimestamp":[131643676396776065],"userprincipalname":["[email protected]"],"employeeid":["99999"],"accountexpires":[9223372036854775807],"department":["DepartmentName"],"codepage":[0],"sn":["Last Name"]}

/* value of properties, the string I concatenated */
"givenname": [{"type": "String", "value"; "First Name"}],
"samaccountname": [{"type": "String", "value"; "User.Name"}],
"cn": [{"type": "String", "value"; "First Name Last name"}],
"pwdlastset": [{"type": "Int64", "value"; "131641282827115142"}],
"whencreated": [{"type": "DateTime", "value"; "12/10/2017 10:16:43 p. m."}],
"badpwdcount": [{"type": "Int32", "value"; "0"}],
"displayname": [{"type": "String", "value"; "First Name Last name"}],
"lastlogon": [{"type": "Int64", "value"; "131648243091569908"}],
"samaccounttype": [{"type": "Int32", "value"; "805306368"}],
"countrycode": [{"type": "Int32", "value"; "0"}],
"objectguid": [{"type": "Byte[]", "value"; "System.Byte[]"}],
"usnchanged": [{"type": "Int64", "value"; "52144153"}],
"manager": [{"type": "String", "value"; "CN=Some Person Name,OU=Department name,OU=City,OU=Group Name,DC=Domain,DC=com"}],
"whenchanged": [{"type": "DateTime", "value"; "2/3/2018 11:21:54 p. m."}],
"name": [{"type": "String", "value"; "First Name Last name"}],
"objectsid": [{"type": "Byte[]", "value"; "System.Byte[]"}],
"lastlogoff": [{"type": "Int64", "value"; "0"}],
"lockouttime": [{"type": "Int64", "value"; "0"}],
"badpasswordtime": [{"type": "Int64", "value"; "131647632246625185"}],
"instancetype": [{"type": "Int32", "value"; "4"}],
"primarygroupid": [{"type": "Int32", "value"; "513"}],
"objectcategory": [{"type": "String", "value"; "CN=Person,CN=Schema,CN=Configuration,DC=Domain,DC=com"}],
"logoncount": [{"type": "Int32", "value"; "1073"}],
"useraccountcontrol": [{"type": "Int32", "value"; "512"}],
"description": [{"type": "String", "value"; "13065, PROGRAMADOR SENIOR"}],
"dscorepropagationdata": [{"type": "DateTime", "value"; "1/1/1601 12:00:00 a. m."}],
"distinguishedname": [{"type": "String", "value"; "CN=First Name Last name,OU=Department name,OU=City,OU=Group Name,DC=Domain,DC=com"}],
"objectclass": [{"type": "String", "value"; "top"},{"type": "String", "value"; "person"},{"type": "String", "value"; "organizationalPerson"},{"type": "String", "value"; "user"}],
"adspath": [{"type": "String", "value"; "LDAP://SERVERNAME/CN=First Name Last name,OU=Department name,OU=City,OU=Group Name,DC=Domain,DC=com"}],
"usncreated": [{"type": "Int64", "value"; "39705915"}],
"lastlogontimestamp": [{"type": "Int64", "value"; "131643676396776065"}],
"userprincipalname": [{"type": "String", "value"; "[email protected]"}],
"employeeid": [{"type": "String", "value"; "13065"}],
"accountexpires": [{"type": "Int64", "value"; "9223372036854775807"}],
"department": [{"type": "String", "value"; "IT"}],
"codepage": [{"type": "Int32", "value"; "0"}],
"sn": [{"type": "String", "value"; "Last name"}]

As you can see, some of the properties have more than one value. So, to get a simple generic list of properties you would need to decide what to do with multi-valued properties. Most likely, you'd like to have all values as strings, so, multiple values can simply be concatenated using a suitable separator.

like image 23
Jahaziel Avatar answered Sep 21 '22 17:09

Jahaziel