Getting a list of all the direct reports for a given user, or similarly building the manager’s chain seems to be a common question lately, so I figured I’d write a short article on this. There are few different ways for us to query this information, so let’s go over them.
First, it’s important to understand which attributes hold the relevant information are. In traditional AD, the manager and directReports (a “backlink”) attributes are used, with the former synchronized to Azure AD when directory synchronization is in use. However, the manager attribute isn’t actually exposed in the output of the good old Get-MsolUser cmdlet, or any of the cmdlets of the MSOnline module for that matter. This changed with the introduction of the Get-AzureADUserManager and Get-AzureADUserDirectReport cmdlets in the Azure AD module, yet being separate cmdlets, they make the process of retrieving this information across a group of users a bit more complicated than it should be.
Get-AzureADUserManager -ObjectId 584b2b38-888c-4b85-8871-c9766cb4791b ObjectId DisplayName UserPrincipalName UserType -------- ----------- ----------------- -------- e0d7442c-8cd8-4e65-8ede-ec9887816677 HuKu HuKu@tenant.onmicrosoft.com Member Get-AzureADUserDirectReport -ObjectId 584b2b38-888c-4b85-8871-c9766cb4791b ObjectId DisplayName UserPrincipalName UserType -------- ----------- ----------------- -------- 064abb3c-0812-44f9-bdcc-eea7e6ea398b Gosho gosho@domain.com Member
Thus, to this day my favorite method of retrieving managerial relationship information within Office 365 remain the Exchange Online cmdlets. To be more specific, the Get-User cmdlet exposes both the manager and directReports attributes, as follows:
Get-User vasil | select -ExpandProperty manager HuKu Get-User vasil | select -ExpandProperty directreports gosho
The bad news is that the output is a plain text “name”, meaning it’s hard to surface additional information, and it creates ambiguity in any moderately large organization. The good news is that the cmdlet supports a robust set of filters, making it possible to address some interesting scenarios. For example, if you want to list all users within the company that have at least one direct reports (or in other words, all “managers”), you can use something like this:
Get-User -Filter {DirectReports -ne $null} Name RecipientType ---- ------------- vasil UserMailbox HuKu UserMailbox
This time, the full object is returned, meaning you can easily expose additional information, for example the UserPrincipalName attribute, so you can avoid any ambiguity. Or you can group by department, giving you a quick way to count the number of managers per department in your organization:
Get-User -Filter {DirectReports -ne $null} | select DisplayName,UserPrincipalName,Department DisplayName UserPrincipalName Department ----------- ----------------- ---------- Vasil Michev user@domain.com HQ HuKu anotheruser@domain.com Sales Get-User -Filter {DirectReports -ne $null} | group Department Count Name Group ----- ---- ----- 1 HQ {vasil} 1 Sales {HuKu}
Do note that if you want to use a filter against a specific user, you will need to provide the value of the DistinguishedName attribute. So if we want to find the manager for a specific user, we can use this:
$dn = Get-User vasil | select -ExpandProperty DistinguishedName Get-User -Filter "DirectReports -eq '$dn'" Name RecipientType ---- ------------- HuKu UserMailbox
which of course we can also do by looking at the manager property, as in our first example. The same set of filters works against the Manager attribute as well. For example, the below will return all the direct reports for HuKu:
$dn = Get-User huku | select -ExpandProperty DistinguishedName Get-User -Filter "Manager -eq '$dn'" Name RecipientType ---- ------------- vasil UserMailbox WC UserMailbox
which of course we can also do by querying the directReports property:
Get-User huku | select -ExpandProperty directReports WC vasil
Without boring you with too many repetitive examples, the rule of thumb is as follows: you can use the Get-User cmdlet to quickly list the manager or direct reports of a given user by checking the values of the appropriate attributes, or create a basic report across all users within the company. If you want to generate a proper report however, you should instead use the filter-based syntax, as it will return the full object, allowing you to expose additional properties and/or remove ambiguity.
Lastly, one can also use the Graph API to obtain this information, which should come as no surprise, given that the Azure AD module is a simple wrapper for Graph. You can query the /manager or /directReports endpoints accordingly, for example:
https://graph.microsoft.com/v1.0/users/user@domain.com/directReports https://graph.microsoft.com/v1.0/users/user@domain.com/manager
The problem with this approach is the limited filtering capabilities in the Graph, and the annoyingly convoluted syntax you need to use at times. For example, you can use the following query to list all users along with their managers:
https://graph.microsoft.com/v1.0/users?$expand=manager&$select=id,displayName
The manager property however will not even be returned for users without a manager set, which is the same behavior as when you didn’t include it in the query. And for the users where it is returned, the full user object will be returned. To request just specific properties, you need to adjust the expand operation as follows:
https://graph.microsoft.com/v1.0/users?$expand=manager($levels=max;$select=id,displayName)&$select=id,displayName&$count=true
where the $count parameter is mandatory and so is the $levels one it seems. Refer to the official documentation for more information on this.
For the directReport query the situation is even more annoying, as the property is always returned (in contrast to the manager one), and there doesnt seem to be a way to request just specific properties (the full user object is always returned). But hey, that’s Graph for you. You’re better off using client-side filtering anyway.