C# - Unsure how to fix errors related to custom classes/types copied from someone else's code

Viewed 49

I am trying to fetch the list of dynamic distribution groups from an Active Directory, and someone pointed me to a Stack Overflow link with code that supposedly works, but I am not 100% sure how to make all the parts of this code work, as the link only contains a portion of their code. I added a couple of using statements and a couple of structs and the DistributionList class at the bottom, but I am unsure of how to get rid of the error that the Settings.ImpersonatedUserDomain line throws because it says that 'ImpersonatedUserDomain' is not defined in 'Settings'. I also am having trouble with the line

dl.DType = new DLT.DDL.set();

because it says that the type name 'DDL' does not exist in the type 'Class2.DLT', even though I have already defined it in the struct below. I'm not sure what I am doing wrong here. I would comment on the Stack Overflow question, but I don't have enough reputation. Can anyone help?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.DirectoryServices;
using System.Configuration;
using System.CodeDom;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
using System.Runtime.ConstrainedExecution;
using System.Security;
using Outlook = Microsoft.Office.Interop.Outlook; 
using Microsoft.Exchange.WebServices.Data;
using NuGet.Configuration;

/* This code may only be usable over a VPN*/
/* Source: https://stackoverflow.com/questions/53431322/looking-for-help-accessing-dynamic-distribution-lists-using-c-sharp-and-adws*/


public class Class2
{
    //public object Settings { get; private set; }

    public List<DistributionList> GetDynamicDistributionLists(string strEmailAddress)
    {
        List<DistributionList> distributionLists = new List<DistributionList>();
        String DomName = "dc=" + Settings.ImpersonatedUserDomain.Replace(".", ",dc="); 

        using (var group = new DirectoryEntry("LDAP://" + DomName))
        {

            using (var searchRoot = new DirectoryEntry("LDAP://" + DomName))
            using (var searcher = new DirectorySearcher(searchRoot, "(&(ObjectClass=msExchDynamicDistributionList)(proxyAddresses=smtp:" + strEmailAddress.Trim() + "))"))
            using (var results = searcher.FindAll())
            {
                foreach (SearchResult result in results)
                {
                    if (result.Properties.Contains("cn") && result.Properties.Contains("msExchDynamicDLFilter"))
                    {
                        DistributionList dl = new DistributionList();


                        dl.DType = new DLT.DDL.set(); 
                        dl.CN = result.Properties["cn"][0].ToString(); // 
                        dl.FILORDN = result.Properties["msExchDynamicDLFilter"][0].ToString(); 
                        distributionLists.Add(dl);
                    }
                }
            }

        }

        return distributionLists;
    }

    public struct DLT
    {
        public List<String> DDL { get; set; }

    }

}

public class DistributionList   
{
    public struct DLT
    {
        public String DDL;
    }

    public DLT DType { get; set; }
    public string CN { get; set; }
    public string FILORDN { get; set; }
    public List<string> Members { get; set; }
}
1 Answers

I led you down this path, so I should probably help you.

That code has some things specific to their implementation that you don't need. Settings.ImpersonatedUserDomain seems to be a setting they created that gets pulled from somewhere else. But it's just the name of the domain. I have no idea what DLT.DDL.set() does, but you probably don't need it.

You should also be looking at the msExchDynamicDLBaseDN attribute too. It may turn out to be the same on every DL, but just in case...

That code also takes the email address of one dynamic DL and gets the details of just that one, where, if I remember correctly, you want to get all of the dynamic DLs on your domain. If I'm correct in that, this is how I would do it:

using System.DirectoryServices;

public class Class2
{
    public static List<DistributionList> GetDynamicDistributionLists()
    {
        var distributionLists = new List<DistributionList>();
        var domain = "example.com";
        
        // Find all dynamic DLs
        using (var searchRoot = new DirectoryEntry($"LDAP://{domain}"))
        using (var searcher = new DirectorySearcher(searchRoot, "(objectClass=msExchDynamicDistributionList)",
            new [] {"cn", "msExchDynamicDLFilter", "msExchDynamicDLBaseDN"}
        ))
        using (var results = searcher.FindAll())
        {
            foreach (SearchResult result in results)
            {
                if (result.Properties.Contains("cn") && result.Properties.Contains("msExchDynamicDLFilter"))
                {
                    var dl = new DistributionList {
                        Name = (string) result.Properties["cn"][0], 
                        Filter = (string) result.Properties["msExchDynamicDLFilter"][0],
                        SearchRoot = (string) result.Properties["msExchDynamicDLBaseDN"][0]
                    };
                    distributionLists.Add(dl);
                }
            }
        }
        
        //Get membership of each DL
        foreach (var dl in distributionLists) {
            using (var searchRoot = new DirectoryEntry($"LDAP://{dl.SearchRoot}"))
            using (var searcher = new DirectorySearcher(searchRoot, dl.Filter, new [] {"distinguishedName"}))
            using (var results = searcher.FindAll())
            {
                foreach (SearchResult result in results)
                {
                    dl.Members.Add((string) result.Properties["distinguishedName"][0]);
                }
            }
        }

        return distributionLists;
    }
}

public class DistributionList   
{
    public string Name { get; set; }
    public string Filter { get; set; }
    public string SearchRoot { get; set; }
    public List<string> Members { get; set; } = new List<string>();
}

Set domain to the name of your domain. This will populate the Members collection with the distinguishedName of each member. You can change that if you'd rather have the email (use the mail attribute), or anything else.

Related