Office 365 Group Owners Report

One of the common questions we are seeing is “can you give me a report of all Group owners?”, and in this article we will discuss the methods available to gather this data. As usual, we will also provide a custom PowerShell script that you can use to generate a sample report.

To begin with, we should identify what users usually mean by “owner”. For those used to the “traditional” AD model, owners of security or distribution groups are identified by the ManagedBy attribute. With the move to the cloud however, things have changed a bit. In the Office 365 world for example, the underlying Azure AD has its own representation of group objects, and while it does include the ManagedBy attribute, no data is surfaced regarding the actual Owner of the group. In fact, if you take a look at the property via the WAAD PowerShell module, you will find that no values are presented, even for synced objects:

Get-MsolGroup | ft DisplayName,ManagedBy,ObjectId

Get-MsolGroup | ? {$_.ManagedBy}

The MangedBy data is in fact synced, as you can easily verify if you check the object properties in the Metaverse. It is simply not “consumed” via Azure AD and thus not exposed to the relevant admin endpoint. Instead, it is stored and forwarded to the workload-specific directories, such as EXODS.

Now, what Azure AD does support is the Owner property. Owners of a group object are any users that can modify the object and the self-service model utilized in Azure AD allows you to designate Owners to variety of objects. To get the list of group Owners, one can use the following Azure AD PowerShell cmdlet:

Get-AzureADGroupOwner -ObjectId 42b59d3f-9987-40ac-9905-f10044b9944e

Get-AzureADGroupOwner -ObjectId (Get-AzureADGroup -SearchString groupname).ObjectId

The Owner property can be configured for any Group object recognized by Azure AD. This includes Security groups, Distribution groups, Mail-enabled security groups, Office 365 groups, dynamic membership groups. The list however does not include any workload-specific groups, for example Dynamic distribution groups from Exchange Online.

So how do you get the Owner report for all groups in the company then? You simply need to get the list of groups and fetch the Owner property via the Get-AzureADGroupOwner cmdlet. Here’s an example:

Get-AzureADGroup -All:$true | select DisplayName,@{n="Owners";e={((Get-AzureADGroupOwner -ObjectId $_.ObjectId).UserPrincipalName -join ";")}}

A group can have multiple owners, thus we are making a small transform of the output to account for that fact. In reality, you would probably want to include some other properties in the report and sort it properly. This example might work better:

Get-AzureADGroup -All:$true | % { $_ | Add-Member "Owners" ((Get-AzureADGroupOwner -ObjectId $_.ObjectId).UserPrincipalName -join ";") -PassThru } | sort DisplayName | select DisplayName,MailEnabled,SecurityEnabled,Owners,ObjectId | ft

And in case you are using the Azure AD Preview module, you can instead use the Get-AzureADMSGroup cmdlet, which surfaces even more information, such as the GroupTypes and information about any dynamic membership rules. Here’s an example:

Get-AzureADMSGroup -All:$true | % { $_ | Add-Member "Owners" ((Get-AzureADGroupOwner -ObjectId $_.Id).UserPrincipalName -join ";") -PassThru } | sort DisplayName | select DisplayName,MailEnabled,SecurityEnabled,GroupTypes,Owners,Id | ft

One must also consider the data stored in workload-specific directories if he wants to get a proper report of all the group owners. As mentioned already, some objects such as Dynamic DGs or Room Lists are not recognized by Azure AD and only exist within the EXODS. In addition, the relation between the ManagedBy attribute for any Exchange group and the Owner property in Azure AD is not so straightforward. In most cases, the Owner property will exactly match the ManagedBy property of the corresponding object, however that’s not always true. Sometimes this information is not written back to Azure AD and moreover, changes made to the Owner property in Azure AD do not propagate to EXODS and do not add/replace the ManagedBy attribute. This in turn means, that if you want to get the full picture, you should query the EXODS as well. Here’s an example cmdlet that will get all objects that support the ManagedBy property:

Get-Recipient -RecipientTypeDetails MailUniversalSecurityGroup,MailUniversalDistributionGroup,DynamicDistributionGroup,RoomList,GroupMailbox | Select-Object -Property Displayname,ManagedBy,PrimarySMTPAddress,RecipientTypeDetails

Better yet, you should combine both datasets, as in turn EXODS has some limitations – for example it will not recognize “plain” security groups and will not surface any information about them. With this in mind, we’ve prepared a sample script you can use to fetch all the relevant data. You can find the script over at GitHub.

A few words about the script. It will detect any existing connections to Azure AD and/or Exchange Online and will reuse them. If no such connections exist, a basic functionality is added to facilitate a new session, but don’t expect this to cover all possible scenarios. For example, the method used to connect to Exchange Online will not work with MFA-enabled accounts. Make sure you handle connectivity to Azure AD and ExO with your custom scripts, if needed.

As mentioned already, the WAAD (MSOL) PowerShell module does not expose owner information, thus the script will use the AzureAD module. If you don’t have it installed, download it from the PowerShell Gallery. If you have the Azure AD Preview module installed as well, it will be used instead of the Azure AD module, as it surfaces some additional information about Group objects.

If you want to include the data from Exchange Online as well, make sure to specify the -IncludeExchangeManagedBy parameter when invoking the script:

.\Groups_Owner_Inventory.ps1 -IncludeExchangeManagedBy

The script will output the report in the host window and store it in the $varOwners and $varOwnersExchange global variables respectively. This allows you to sort or modify the output before exporting it, but if you prefer to export it directly simply remove the comment marks from lines 73 and 79. Of course, feel free to make any other modifications to the script you see fit.

Lastly, you should be aware of the fact that the ManagedBy data returned by Exchange is just the display name of the user, which means the output might be non-deterministic. In contrast, Azure AD will return the full object and thus you can fetch a unique-valued property such as the UserPrincipalName or ObjectId.

This entry was posted in Azure AD, Exchange Online, Microsoft 365, Office 365, PowerShell. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.