如何将 PropertyValueCollection 转换为 C# 列表? (结果属性集合和搜索结果)

发布于 12-15 12:56 字数 664 浏览 3 评论 0原文

我编写了一个查询来从 Active Directory 中读取一些内容,但结果是某种“ResultPropertyCollection”,这是我不熟悉的东西。

如何将此结果转换为我更熟悉的列表(例如通用列表),以便我可以对结果执行某些操作?

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();

I've written a query to read some stuff from Active Directory, but the result is some kind of "ResultPropertyCollection", which is something I'm not familiar with.

How can I convert this result to a list (like Generic List) that I'm more familiar with so I can do something with the results?

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();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

韬韬不绝2024-12-22 12:56:13

如果您只需要 SearchResult 类型的列表,您可以使用:

var r = ds.FindAll();
        
List<SearchResult> results = new List<SearchResult>();

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

但由于您需要搜索结果中的实际值,因此您需要做更多的工作。

基本上,该集合包含您为搜索定义的所有属性 - 至少只要它们包含值!

所以实际上,您需要做的是创建一个类来保存这些值。两个元素 memberOfmember 本身可以包含多个值(它们是 AD 中的“多值”属性) - 因此您需要这些值的字符串列表:

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; }
}

然后,一旦获得搜索结果,您需要迭代结果并为每个搜索结果创建 YourType 的新实例,并将它们粘贴到 List 中>:

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

在该方法中,您需要检查每个值的 .Properties 集合并提取它:

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 extract

    return returnValue;
}

If you only want 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 since 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 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 extract

    return returnValue;
}
给不了的爱2024-12-22 12:56:13

一开始我也很困惑,但这都是获取属性集合项类型的问题。一旦我发现属性项的类型是 System.Collections.DictionaryEntry 并且该值是由 ResultPropertyValueCollection 项组成的集合,就可以进行简单的迭代。

这是我最终得到的结果:

        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;

请注意使用 JsonConvert.SerializeObject 快速轻松地转换为字符串。这是一步转换。

我还使用 foreach 迭代执行了到字符串的个性化转换。这更像是一种自学练习,我从中了解到,在获得命名属性的值后,我可以找出该属性是否有零个、一个或多个值,并采取相应的行动,甚至在必要时验证对象类型。

这是在字符串变量、属性和 userData 中获得的值(出于隐私原因删除了一些项目)。

/* 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"}]

正如您所看到的,某些属性具有多个值。因此,要获得简单的通用属性列表,您需要决定如何处理多值属性。最有可能的是,您希望将所有值都作为字符串,因此可以使用合适的分隔符简单地连接多个值。

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.

墟烟2024-12-22 12:56:13

这可能不是完整的解决方案或正确的答案。
下面只是将 SearchResultCollection 转换为 List 的解决方案

SearchResultCollection rc = ds.FindAll();

List<SearchResult> resultList = rc.Cast<SearchResult>().ToList();

// Now loop through the list
foreach(SearchResult sr in resultList)
{
    //.. get properties here
}

This might not be a complete solution or the proper answer.
Below is only a solution to convert SearchResultCollection to List

SearchResultCollection rc = ds.FindAll();

List<SearchResult> resultList = rc.Cast<SearchResult>().ToList();

// Now loop through the list
foreach(SearchResult sr in resultList)
{
    //.. get properties here
}
难得心□动2024-12-22 12:56:13

我们不能使用这样的东西吗? (因为我现在正在使用它)

ds.FindAll().Cast<SearchResult>().Select(result => new Address(result.GetDirectoryEntry())).ToList();

public class Address
{
    internal Address(DirectoryEntry entry)
    {
        //
        // You can get one or more of the following properties:
        //
        //
        // objectClass
        // cn
        // description
        // givenName
        // distinguishedName
        // instanceType
        // whenCreated
        // whenChanged
        // displayName
        // uSNCreated
        // memberOf
        // uSNChanged
        // homeMTA
        // proxyAddresses
        // homeMDB
        // mDBUseDefaults
        // mailNickname
        // protocolSettings
        // name
        // objectGUID
        // userAccountControl
        // badPwdCount
        // codePage
        // countryCode
        // badPasswordTime
        // lastLogon
        // pwdLastSet
        // primaryGroupID
        // objectSid
        // accountExpires
        // logonCount
        // sAMAccountName
        // sAMAccountType
        // showInAddressBook
        // legacyExchangeDN
        // userPrincipalName
        // lockoutTime
        // objectCategory
        // dSCorePropagationData
        // lastLogonTimestamp
        // textEncodedORAddress
        // mail
        // msExchPoliciesExcluded
        // msExchMailboxTemplateLink
        // msExchRecipientDisplayType
        // msExchUserCulture
        // msExchVersion
        // msExchRecipientTypeDetails
        // msExchHomeServerName
        // msExchALObjectVersion
        // msExchMailboxSecurityDescriptor
        // msExchUserAccountControl
        // msExchMailboxGuid
        // nTSecurityDescriptor

        // As an example we get only two properties
        this.DisplayName = (string)entry.Properties["displayName"].Value;
        this.Mail = (string)entry.Properties["mail"].Value;
        Manager = (string)entry.Properties["manager"].Value;
    }

    public string DisplayName
    {
        get;
        private set;
    }

    public string Manager
    {
        get;
        private set;
    }

    public string Mail
    {
        get;
        private set;
    }
}

Can't we use something like this? (As I am currently using it)

ds.FindAll().Cast<SearchResult>().Select(result => new Address(result.GetDirectoryEntry())).ToList();

public class Address
{
    internal Address(DirectoryEntry entry)
    {
        //
        // You can get one or more of the following properties:
        //
        //
        // objectClass
        // cn
        // description
        // givenName
        // distinguishedName
        // instanceType
        // whenCreated
        // whenChanged
        // displayName
        // uSNCreated
        // memberOf
        // uSNChanged
        // homeMTA
        // proxyAddresses
        // homeMDB
        // mDBUseDefaults
        // mailNickname
        // protocolSettings
        // name
        // objectGUID
        // userAccountControl
        // badPwdCount
        // codePage
        // countryCode
        // badPasswordTime
        // lastLogon
        // pwdLastSet
        // primaryGroupID
        // objectSid
        // accountExpires
        // logonCount
        // sAMAccountName
        // sAMAccountType
        // showInAddressBook
        // legacyExchangeDN
        // userPrincipalName
        // lockoutTime
        // objectCategory
        // dSCorePropagationData
        // lastLogonTimestamp
        // textEncodedORAddress
        // mail
        // msExchPoliciesExcluded
        // msExchMailboxTemplateLink
        // msExchRecipientDisplayType
        // msExchUserCulture
        // msExchVersion
        // msExchRecipientTypeDetails
        // msExchHomeServerName
        // msExchALObjectVersion
        // msExchMailboxSecurityDescriptor
        // msExchUserAccountControl
        // msExchMailboxGuid
        // nTSecurityDescriptor

        // As an example we get only two properties
        this.DisplayName = (string)entry.Properties["displayName"].Value;
        this.Mail = (string)entry.Properties["mail"].Value;
        Manager = (string)entry.Properties["manager"].Value;
    }

    public string DisplayName
    {
        get;
        private set;
    }

    public string Manager
    {
        get;
        private set;
    }

    public string Mail
    {
        get;
        private set;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文