Table of Contents
Find Manager for Entra ID Accounts is Easy at the Individual Level
Following Friday’s discussion about needing to update the script to create the Managers and Direct Reports report, I was asked what’s the best way to find managers assigned to Entra ID user accounts (Figure 1).
It is simple to find and report the manager for an individual user account with PowerShell. For instance, to find Sean Landy’s manager, run the Get-MgUserManager cmdlet. The return value is the object identifier for the manager’s account, so to find details of the manager, we must fetch it from the data stored in the additionalProperties property.
Get-MgUserManager -UserId Sean.Landy@office365itpros.com | Select-Object -ExpandProperty additionalproperties Key Value --- ----- @odata.context https://graph.microsoft.com/v1.0/$metadata#directoryObjects/$entity @odata.type #microsoft.graph.user businessPhones {+353 1 8816644} displayName James Ryan givenName James jobTitle Chief Story Teller mail James.Ryan@office365itpros.com
The Manager property is in the set available to Get-MgUser, but it must be fetched to be available for processing. The property is a reference to another account, so it must be resolved by using the ExpandProperty parameter. Again, the manager’s display name is retrieved from the additionalProperties property.
$UserData = Get-MgUser -UserId Sean.Landy@office365itpros.com -Property displayname, manager -ExpandProperty Manager $UserData | Format-Table @{n='Employee'; e={$_.displayname}}, @{n='Manager'; e={$data.manager.additionalproperties['displayName']}} Employee Manager -------- ------- Sean Landy James Ryan
Find the Managers for Multiple Users
Challenges emerge when dealing with multiple user accounts. For example, it’s common to retrieve the set of licensed user accounts in a tenant with a complex query that checks for the presence of at least one license. However, adding the ExpandProperty parameter to this command stops it working:
[array]$users = Get-MgUser -Filter "userType eq 'Member' and assignedLicenses/`$count ne 0" -ConsistencyLevel eventual -CountVariable UsersFound -All -PageSize 999 -Property Id, userPrincipalName, displayName, Manager, Department, JobTitle, EmployeeId -ExpandProperty Manager
The error is not terribly helpful:
Expect simple name=value query, but observe property 'assignedLicenses' of complex type 'AssignedLicense'.
Removing the ExpandProperty parameter from the command makes it work, but the Manager property is not populated.
Any filter to find user accounts that needs to populate the Manager property is restricted to a simple query. Here’s an example of a query to find all member accounts and populate the Manager property. A client-side filter then reduces the set to accounts with an assigned manager:
[array]$EmployeesWithManager = Get-MgUser -All -PageSize 999 -Property Id, DisplayName, JobTitle, Department, City, Country, Manager -ExpandProperty Manager -Filter "UserType eq 'Member'"| Where-Object {$_.Manager.id -ne $null} $EmployeesWithManager | Format-Table id, displayname, @{Name='Manager';expression={$_.Manager.additionalProperties.displayName}} -Wrap Id DisplayName Manager -- ----------- ------- a3eeaea5-409f-4b89-b039-1bb68276e97d Ben Owens James Ryan d446f6d7-5728-44f8-9eac-71adb354fc89 James Abrahams Kim Akers cad05ccf-a359-4ac7-89e0-1e33bf37579e James Ryan René Artois
The results generated by this code are acceptable because a user account with an assigned manager is probably one used by a human. The account probably has licenses too. Obviously, any account that hasn’t got an assigned manager will be left out of the report.
Looking for User Accounts without Managers
Things get a little more difficult if we reverse the client-side filter and look for member accounts that don’t have an assigned manager:
[array]$EmployeesWithoutManager = Get-MgUser -All -PageSize 999 -Property Id, DisplayName, JobTitle, Department, City, Country, Manager, UserPrincipalName -ExpandProperty Manager -Filter "UserType eq 'Member'"| Where-Object {$_.Manager.id -eq $null}
In addition to user accounts lacking managers, the set of resulting accounts will include utility accounts created by Exchange Online, including:
- Room and equipment accounts.
- Shared mailbox accounts.
- Accounts used for Microsoft Bookings.
- Accounts synchronized from other tenants in a multi-tenant organization (MTO).
- Accounts created for submission of messages to the Exchange Online High Volume Email (HVE) solution.
- Accounts created for Teams meeting rooms.
- Service accounts created by the tenant for background processing and other reasons.
In a medium to large tenant, there might be thousands of these kinds of accounts cluttering up the view. To remove the utility accounts, create an array containing the object identifiers of the owning accounts:
[array]$CheckList = Get-ExoMailbox -RecipientTypeDetails RoomMailbox, EquipmentMailbox, SharedMailbox, SchedulingMailbox -ResultSize Unlimited | Select-Object -ExpandProperty ExternalDirectoryObjectId
If the tenant uses HVE, add the account identifiers for the HVE accounts to the array.
Get-MailUser -LOBAppAccount | ForEach { $Checklist += $_.ExternalDirectoryObjectId }
Now filter the account list to find those that don’t appear in the list of utility mailboxes:
$EmployeesWithoutManager = $EmployeesWithoutManager | Where-Object {($_.Id -notin $Checklist)}
If the tenant is part of a multi-tenant organization, this filter removes the accounts synchronized from the other tenants:
$EmployeesWithOutManager = $EmployeesWithoutManager | Where-Object {$_.UserPrincipalName -notlike "*#EXT#@*"}
Eventually, you’ll end up with hopefully a very small list of employees without assigned managers and can take the necessary action to rectify the situation.
Entra ID Should Mark Utility Accounts
The problem of dealing with utility accounts that end up in Entra ID with the same status as “human” user accounts is growing. Applications create new member accounts without thinking about the consequences. No problem is apparent because no licenses are consumed, but the steps needed to cleanse the set of accounts returned by Entra ID with cmdlets like Get-MgUser are another trap waiting for the unwary administrator. Microsoft really should do better in this area, like creating a new “utility” value for the UserType property. Would that be so bad?
Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.
Not only utility accounts, but also rooms and equipment. All of them have associated user resource
I believe that point is made in the article.
I agree, Entra is becoming a mess and it’s difficult to report for example who is registered for MFA, when the built-in report gives me Shared Mailboxes and other things.
For managers, we utilize EmployeeType property in AD (employee, contractor, service, etc).
I populate a group of just managers of employees & contractors.
$users = Get-MgUser -Filter “employeeId ne null” -all -ConsistencyLevel eventual -CountVariable CountVar
ForEach ($user in $users){
if (Get-MgUserDirectReport -UserId $user.id -All) {
$manager = $user
#get all direct reports
$allDirects = Get-MgUserDirectReport -UserId $manager.id -All
# add manager to manager array if the employeetype of the direct report is valid.
foreach ($direct in $allDirects) {
$employeeType = (Get-MgUser -UserId $direct.id -Property extension_72865f8793294a44b04f437101a06033_employeeType).additionalproperties.extension_72865f8793294a44b04f437101a06033_employeeType
if (($employeeType -eq “Employee”) -or ($employeeType -eq “Vendor”) -or ($employeeType -eq “Temp”) -or ($employeeType -eq “Contractor”)) {
$managers += $manager
# we only need to find one valid direct report, then we can move to the next manager.
break
}
}
}
}
I then compare the array to the existing group members and add or subtract if needed.
It takes about 10 min to run for 3000 users.
There is an EmployeeType property. Is there any reason why you don’t use it?
It doesn’t populate from AD Connect so we have to use the extension.
Got it. Good reason!
I actually checked again and it appears to populate now after 2 years of using this script
Get-MgUser -UserId -Property employeetype |select employeetype
EmployeeType
————
Employee
Hah! We get this kind of thing all the time as we maintain the content of the Office 365 for IT Pros eBook…
I forgot to mention. The main reason why we use the employeeType extension is because the Dynamic Rules in groups doesn’t include user.employeeType. Kind of a head scratcher why they haven’t included that.