How to programmatically get all Mailbox Databases from Active Directory using C#…

by Andy Grogan on May 19, 2013 · 1 comment

in Exchange 2010 (Databases), Exchange 2013 (Databases), Exchange 2013 (Mailboxes), Exchange Programming .NET, Windows Server 2012 [ Active Directory ]

Ok, so I was thinking (which is always a very dangerous thing!) – after my last post on how you can programmatically count Mailboxes per Exchange Database – I was wondering how you can programmatically get a list of all Exchange Mailbox Databases in Active Directory via their distinguishedName.

Why was I thinking this? – well, if you were interested in – or – read my last article you would have noted that in order to “count” the Mailboxes within each database you had to supply (from the command line) the distinguishedName of each Mailbox database to the code.

Now, I am all about automation – so I wanted to define a way where the same code (from my previous post) could be executed to display the same data without the need for command line arguments – e.g the mailbox counts per database without the user having to provide the distinguishedName.

So, I had a good old session on MSDN and eventually found this code sample which gave me what I needed. In essence I knew that I wanted to be able to search the Active Directory “Configuration Partition” in the same way as I did with the “Domain Partition” (where the Domain contains properties and attributes for user account objects (amongst other things)).

The idea was if I could get the distinguishedName of a Mailbox Database from the AD Configuration Partition using an LDAP filter and then pass the result to a LDAP search of the “Domain Partition” partition based on the “homeMDB” attribute (see last post) – then I could automate the entire process – therefore negating the need for command line arguments.

So I have added the following function to he code:

static void GetMailboxDatabases()
        {
            
            DirectoryEntry RootDSE = new DirectoryEntry("LDAP://RootDSE");
            DirectoryEntry ConfigContainer = new DirectoryEntry("LDAP://" + RootDSE.Properties["configurationNamingContext"].Value);
            
            DirectorySearcher ConfigSearcher = new DirectorySearcher(ConfigContainer);
            ConfigSearcher.Filter = "(&(objectClass=msExchMDB))";
            ConfigSearcher.PropertiesToLoad.Add("distinguishedName");
            ConfigSearcher.PageSize = 10000;
            ConfigSearcher.SearchScope = SearchScope.Subtree;


            foreach (SearchResult result in ConfigSearcher.FindAll())
            {
                
                GetDatabaseMailboxCount(result.Properties["distinguishedName"][0].ToString());

            }
        }

As mentioned – the function above is based upon a generic MSDN article – which I have made a few modifications to – these are:

  • The original MSDN code performs an LDAP search of the Configuration Partition in AD (which also contains a number of Exchange specific attributes when Exchange is installed) – I changed the LDAP search filter to:
(&(objectClass=msExchMDB)
  • I modified the PageSize to 10000 – to ensure that the traversal of the AD tree was deep enough (in large environments this *might* need increasing).
  • Modified the SearchScope to SubTree – to ensure that all levels of the configuration partition are traversed during the search.
  • Added in a “foreach” loop as we expect multiple results (e.g. more than one Database) to pass the Database DN to the DatabaseMailboxCount function.

The modified code

The original code needed arguments from the command line when compiled – the revised code (below) works like the following:

  • Does not need the Mailbox Database Distinguished Name to be passed from the command line.
  • Only gets “real” mailboxes (e.g. no System or Health Mailboxes).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;

namespace GetDatabaseMailboxCount
{
    class Program
    {

        /*
         Define a function that gets the Root Directory Entry Path.
         This is used by other functions to return the default naming context:
         LDAP://DC=artTest,DC=local
         */

        public static DirectoryEntry GetDirectoryEntry()
        {
            try
            {
                DirectoryEntry Root = new DirectoryEntry("LDAP://RootDSE");
                string Domain = (string)Root.Properties["defaultNamingContext"][0];

                DirectoryEntry DirectoryENT = new DirectoryEntry();

                DirectoryENT.Path = "LDAP://" + Domain;
                DirectoryENT.AuthenticationType = AuthenticationTypes.Secure;

                return DirectoryENT;
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Failed to contact Active Directory with error: \n{0}", ex.Message);
                Console.ResetColor();
                return null;
            }
        }

        /*
         
         Define the function which Counts the Mailboxes per Database
         
         
         */

        static void GetDatabaseMailboxCount(string MailboxDN)
        {
            
            // Get the Directory Path
            
            string aDE = GetDirectoryEntry().Path.ToString();
            
            // Create a Directory Searcher Object Set to the Path

            DirectorySearcher search = new DirectorySearcher(aDE);

            string filter;


                // Otherwise filter out cn= starting with HealthMailbox or SystemMailbox
                
                filter = "(&(objectClass=user)(homeMDB=" + MailboxDN + ")(!(cn=HealthMailbox*))(!(cn=SystemMailbox*)))";
            
            search.Filter = filter;
            search.PageSize = 10000;
            search.SearchScope = SearchScope.Subtree;
            
            int Number = 0;

            // Count each result

            foreach (SearchResult result in search.FindAll())
            {
                Number++;
            }

         
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Mailbox Database: " + MailboxDN + ":");
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine("Contains " + Number + " Mailboxes");
            Console.ResetColor();

        }

        static void GetMailboxDatabases()
        {
            
            DirectoryEntry RootDSE = new DirectoryEntry("LDAP://RootDSE");
            DirectoryEntry ConfigContainer = new DirectoryEntry("LDAP://" + RootDSE.Properties["configurationNamingContext"].Value);
            
            DirectorySearcher ConfigSearcher = new DirectorySearcher(ConfigContainer);
            ConfigSearcher.Filter = "(&(objectClass=msExchMDB))";
            ConfigSearcher.PropertiesToLoad.Add("distinguishedName");
            ConfigSearcher.PageSize = 10000;
            ConfigSearcher.SearchScope = SearchScope.Subtree;


            foreach (SearchResult result in ConfigSearcher.FindAll())
            {
                
                GetDatabaseMailboxCount(result.Properties["distinguishedName"][0].ToString());

            }
        }

        static void Main(string[] args)
        {
            Console.Clear();
            GetMailboxDatabases();

        }
    }
}

Hope that helps!

Social

{ 1 comment… read it below or add one }

merlin April 29, 2015 at 4:16 pm

To get a list of enabled user accounts from LDAP, without any service accounts of any kind, you could try including this:

(&(!(UserAccountControl:1.2.840.113556.1.4.803:=2))(msExchRecipientTypeDetails=1))

Reply

Leave a Comment

Previous post:

Next post: