Nested DL Membership in Exchange 2007

Aeons ago, Vivek posted about how to get DL membership in Exchange 2007. He commented that "This can be adapted to do nested membership as well—I’ll leave it to you to figure out how. "

At the time, I remember reading this and thinking briefly about how I'd do this, but never really sitting down and doing it to prove my idea was correct.

Well, my time finally ran out on not looking at this. The other day, someone sent me a semi-working PowerShell function to get DL membership (including recursion) and asked me how to make it detect looping recursion. It's been over a year since Vivek delegated this problem "to you", so I guess that's about enough time and we should share an answer. Let's get to it!

Here's the function we started with:

function Get-DLMemberRecurse
{
                foreach ($varTemp in get-distributiongroupmember $args[0])
                {
                                $varTemp
                                if ($varTemp.RecipientType -like "Mail*Group") { Get-DLMemberRecurse $varTemp.Identity }
                }
}

Key problem? If you have DG1 which has DG2 as a member which then has DG1 as a member (a looping membership hierarchy which is totally possible to set, but totally useless practically), it loops forever until it overflows the stack. Whoops, that's no good!

So we need to make a couple of changes to solve this problem. We need to do at least two things (which I've color coded in my updated function below to highlight the changes):

  • Add some recursion protection, using PowerShell’s understanding of scope and recursion. This is useful to ensure we can effectively reset and subsequently build a list of DGs we’ve already traversed.
  • Build a list of DGs we’ve traversed, and update it each time we find a new one

function Get-DLMemberRecurse
{

      $ParentScriptBlock = (get-variable -scope 1 MyInvocation -value).MyCommand.ScriptBlock;
if($ParentScriptBlock -ne $MyInvocation.MyCommand.ScriptBlock)
{
# we're not recursing (we should only hit this once and we'll use it to reset the DGList)

            $global:DGList = @()
$global:DGList += (Get-DistributionGroup $args[0]).Identity
}
foreach ($varTemp in get-distributiongroupmember $args[0])
{
$varTemp

            if ($varTemp.RecipientType -like "Mail*Group" -and -not ($global:DGList -contains $varTemp.identity) ) { $global:DGList += $varTemp.Identity; Get-DLMemberRecurse $varTemp.Identity }

      }

}

Special thanks to my buds on the PowerShell team for getting me going with the "how to know if I'm inside a recursion loop using MyInvocation variable" tip.