Back to blog

New PowerShell Script: Office 365 Group Owners

Nov 16, 2017 by Vasil Michev

One of the most common Office 365 reporting questions we see is: “How can I get a report of all Group owners?”, so in this post we’ll discuss the methods available to gather this data, and 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, 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 ManagedBy data is in fact synced, this is easy to verify if you check the object properties in the Metaverse. It is simply not “consumed” via Azure AD and therefore is 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 a 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, and dynamic membership groups. The list however does not include any workload-specific groups, for example Dynamic distribution groups from Exchange Online.

Read more how to get your team on 'Teams'

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, which means we’re making a small change to 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

If you are using the Azure AD Preview module, you can use the Get-AzureADMSGroup cmdlet instead, which surfaces even more information, such as the GroupTypes and information about any dynamic membership rules. Here’s an example:powershell
Get-AzureADMSGroup -All:$true | % { $_ | Add-Member “Owners” ((Get-AzureADGroupOwner -ObjectId $_.Id).UserPrincipalName -join “;”) -PassThru } | sort DisplayName | select DisplayName,MailEnabled,SecurityEnabled,GroupTypes,Owners,Id | ft

If you want to get a proper report of all the group owners, it is important to consider the data stored in workload-specific directories. 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 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 at the TechNet Gallery.

Read more how to get your team on 'Teams'

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 Azure AD 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, so you can fetch a unique-valued property such as the UserPrincipalName or ObjectId.

If you’re interested in getting more tips and guidance on using PowerShell to manage Office 365, why not check out our Office 365 scripting workshop with MVP Alan Byrne?