There are a gazillion PowerShell scripts out there that can generate a report of group membership, so one might wonder why I decided to create yet another one. Mostly, because I like things done in a certain way, which in the case of generating a membership report means “by utilizing server-side filtering and the MemberOf attribute”. In addition, most of the scripts generate the report by expanding the membership of each group, while often times people are interested doing the “opposite”. While this can be done easy enough in Excel or similar, this correlation happens to be exactly what the value of the MemberOf attribute returns, so querying it seemed like the natural approach.
This method, as described in a previous blog post, is simple, quick and efficient. It does not require you to iterate over the list of all groups in the organizations just to check whether a particular user is a member of the group. Instead, it takes a single execution of the Get-Recipient cmdlet, and lets the server do the work for you. Combining this with the Invoke-Command implicit remoting method, which allows you to further minimize the data received, and thus the time it takes to complete the script, you end up with a faster and more reliable method to generate the report.
So what exactly does the script do? In a nutshell, it gets the list of recipients you want to generate the report for, then for each recipient uses server-side filtering to quickly get the list of groups, which then gets outputted to the console and saved to a CSV. Since we a re using the Exchange cmdlets, only groups recognized by Exchange will be included in the report: Distribution groups, Mail-Enabled Security groups and Office 365 (modern) groups.
The bulk of the script is contained within the Get-DGMembershipInventory function, with another function introduced to check connectivity to Exchange. The script will detect and reuse any existing sessions to Exchange Remote PowerShell. Basic functionality to facilitate a new connection is also included, but it does not cover all possible scenarios. If you are using an MFA-protected account or any of the non-MT Office 365 instances, make sure you connect manually before running the script. If you need help connecting PowerShell to Exchange Online, follow the steps in this article: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx
The script can be dot-sourced to expose said cmdlets and takes parameters via splatting. Speaking of parameters, by default the script will generate the inventory only for User mailboxes. If you want to include other recipient types, use the corresponding switch parameters, namely:
Running the script without parameters is the same as using the –IncludeUserMailboxes switch. Here’s an example of including User mailboxes and Guest users:
.\DG_MemberOf_inventory.ps1 -IncludeGuestUsers -IncludeUserMailboxes
To identify the recipient, the PrimarySMTPAddress attribute is used. If the recipient does not have this attribute populated (which might be the case for Guest users), the ExternalEmailAddress is used instead, failing that the ExternalDirectoryObjectID identifier is used. For the groups list, the PrimarySMTPAddress attribute is used. If you want to use a different attribute instead, don’t forget to add them to the relevant script blocks inside the Invoke-Command instances, as no other attributes are returned from the implicit remoting session.
If you have a large number of recipients in your organization, it’s a good idea to add some artificial delay between each iteration in order to combat throttling. This can be done by uncommenting line 100, or by adding proper logic to the script, as described in this article.
The script will save the report to a CSV file in the working directory and will also store it in a global variable ($varDGMemberOf) for reuse. Here’s an example of what the report might look like:
You can download the script from GitHub here: https://github.com/michevnew/PowerShell/blob/master/DG_MemberOf_inventory.ps1
Do let me know if you run into any issues with the script or have comments on it.