Exchange 2010 - Universal DL members not being removed via Powershell in mixed 2012 R2/2003 Domains

Hello all,

I am wondering if people have seen issues with Universal DLs where members are not removed from the DLs. DLs are being populated through a query from an Oracle Database. Membership is removed and repopulated nightly. Scripts are written in powershell to check to see if DL exists, if it does remove members and repopulate.

We are currently in a mixed 2003/2012 R2 DC environment and are migrating to 2012 R2 shortly.

Much of what I have read indicates that Global Catalog replication seems to be a problem when updating Universal groups. This may lead to DL corruption. The process is ok in the beginning and through testing, but over a week or so the DLs dont drop members. 

Has anyone experienced issues with DL members not being removed in the mixed DC scenario? Are there any rock solid solutions.

I should add the DLs are created with accounts that are org admins and managed by those accounts.

Any help appreciated.

February 4th, 2015 5:41pm

Thanks Fred,

To answer questions.

1. All DCs in the forest are GCs. I will look at Infrastructure Master which is a Pure root domain with 2 child domains.

2. Im trying to assess all failures or some. I see it getting worse over time. From what I have been reading updating all GCs can cause DL corruption, but from DL perspective Universal DL are the only type created. I have thought about creating local DLs though AD and populating that way, but this becomes more -problematic.

As for logging I need to enhange the logging capability for all of this to do a dictionary of hash table check. Problem is scalability with 1000 dls with siginificant members in each. A great suggestion from you though. If you have any ideas on differential comparison that would be fast would be good.


Free Windows Admin Tool Kit Click here and download it now
February 17th, 2015 12:49pm

Thanks Allen.

I willl look at all documents.

February 17th, 2015 12:50pm

Hi,

well, I do have some ideas on speeding it up.

  1. First of all, you could pre-initialize the dictionary to maximum size necessary (Number of Users in Group + Number of Users Database says ought to be in there). This saves you time from resizing.
  2. Optimize Data Lookup: Use ADSI to only lookup the properties you actually need (User: DN and whatever you need to map to DB Entry; Group: DN and Members). Only search for users once and create a reference dictionary for later use.
  3. Multithread processing. If you have the processing capacity to use, why not have Powershell run in multiple threads?
  4. Minimize scaling overhead for object generation.

Here's some C# code that can do 1) for you and be helpful in 4) too:

# The source code
$source = @"
namespace Netzwerker.Utility
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// Class that contains methods that return specific kinds of objects that are hard to generate directly from Powershell (especially generics)
    /// </summary>
    public static class New
    {
        /// <summary>
        /// Returns a dictionary with the predefined types of key and value.
        /// </summary>
        /// <param name="Key">The type of the Dictionary Key.</param>
        /// <param name="Value">The type of the Dictionary Value.</param>
        /// <param name="Size">The initial Size of the dictionary. Increase for better performance, reduce for less memory consumption.</param>
        /// <returns>Returns a dictionary with the predefined types of key and value.</returns>
        public static object Dictionary(Type Key, Type Value, int Size)
        {
            Type genericClass = new Dictionary<string, int>().GetType().GetGenericTypeDefinition();
            Type constructedClass = genericClass.MakeGenericType(Key, Value);
            return Activator.CreateInstance(constructedClass, Size);
        }

        /// <summary>
        /// Creates an empty, generic list of the appropriate type.
        /// </summary>
        /// <param name="T">The Type of the class to create</param>
        /// <returns>A System.Collections.Generic.List object of the passed type</returns>
        public static object List(Type T)
        {
            Type genericClass = new List<string>().GetType().GetGenericTypeDefinition();
            Type constructedClass = genericClass.MakeGenericType(T);
            return Activator.CreateInstance(constructedClass);
        }
    }

    public struct UserEntry
    {
        public string UserDN;
        public string GroupDN;
        public bool Old;
        public bool New;

        public UserEntry(string UserDN, string GroupDN, bool Old, bool New)
        {
            this.UserDN = UserDN;
            this.GroupDN = GroupDN;
            this.Old = Old;
            this.New = New;
        }

        public bool ToAdd
        {
            get
            {
                return ((!Old) && New);
            }
        }

        public bool ToRemove
        {
            get
            {
                return ((!New) && Old);
            }
        }
    }
}
"@

# Add C# Code
Add-Type $source

# Create a new, presized Dictionary
$Dictionary = [Netzwerker.Utility.New]::Dictionary("String", "Netzwerker.Utility.UserEntry", 2000)

Basically you fill the info from DB and DL for each user in such an object, and the UserEntry will automatically process the ToAdd and ToRemove properties.

Regarding 3, you may find this function useful. Note that you need not necessarily use default limits for concurrent threads. Exceeding the number of cores available is fully valid if there's some waiting period involved (like AD interaction).

As for 2, you can initially search and generate a list of all users and universal groups each and store it in a properly sized dictionary which can later be looked up.

Cheers,
Fred

Free Windows Admin Tool Kit Click here and download it now
February 18th, 2015 4:13am

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics