Last active
March 14, 2025 21:00
-
-
Save joerodgers/f9fc778e3c029a04c082ea4095165c5b to your computer and use it in GitHub Desktop.
Generates a .csv file which can be uploaded to Viva Insights for custom reporting based on manager reporting chain.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#requires -modules "Microsoft.Graph.Authentication", "Microsoft.Graph.Users" | |
function Get-ManagerHierarchy | |
{ | |
[CmdletBinding()] | |
param | |
( | |
[Parameter(Mandatory = $true)] | |
[string] | |
$Identity | |
) | |
begin | |
{ | |
$level = $counter = 1 | |
$managerHierarchyUri = '/v1.0/users/{0}?$expand=manager($levels=max;$select=userPrincipalName)&$select=id,displayName,department,jobTitle,userPrincipalName' -f $Identity | |
} | |
process | |
{ | |
$response = Invoke-MgGraphRequest -Method GET -Uri $managerHierarchyUri -Headers @{ "ConsistencyLevel" = "eventual" } | |
if( $response ) | |
{ | |
$output = [PSCustomObject] @{ | |
UserPrincipalName = $response.userPrincipalName | |
Department = $response.department | |
JobTitle = $response.jobTitle | |
ManagerId = $response.manager.userPrincipalName | |
} | |
$manager = $response.manager | |
$managerHierarchy = while ( $manager ) | |
{ | |
[PSCustomObject] @{ | |
UserPrincipalName = $manager.userPrincipalName | |
Level = $level++ | |
} | |
$manager = $manager.manager | |
} | |
foreach( $manager in $managerHierarchy | Sort-Object -Property "Level" -Descending ) | |
{ | |
$output | Add-Member -MemberType "NoteProperty" -Name "Level$counter" -Value $manager.UserPrincipalName | |
$counter++ | |
} | |
# useful for csv output since you could have a varying number of columns based on reporting depth | |
$output | Add-Member -MemberType "NoteProperty" -Name "ManagerHierarchyDepth" -Value $managerHierarchy.Count | |
return $output | |
} | |
else | |
{ | |
Write-Error "Unable to find user with identity: '$($Identity)'" | |
} | |
} | |
end | |
{ | |
} | |
} | |
# requires Microsoft Graph > Application > User.Read.All | |
Connect-MgGraph -ClientId $env:CDX_CLIENTID ` | |
-CertificateThumbprint $env:CDX_THUMBPRINT ` | |
-TenantId $env:CDX_TENANTID ` | |
-ErrorAction Stop | Out-Null | |
$skuId = "06ebc4ee-1bb5-47dd-8120-11324bc54e06" # Microsoft 365 E5 | |
$skuid = "18a4bd3f-0b5b-4887-b04f-61dd0ee15f5e" # Microsoft Copilot | |
# get all users assigned a specific license | |
$users = Get-MgUser -Filter "assignedLicenses/any(i:i/SkuId eq $skuId)" ` | |
-ConsistencyLevel Eventual ` | |
-Property userPrincipalName, manager ` | |
-ExpandProperty manager ` | |
-All ` | |
-ErrorAction Stop | |
# remove all users without a manager assigned | |
$users = $users | Where-Object -FilterScript { $null -ne $_.manager.Id } | |
# get the reporting change for all users | |
$results = foreach( $user in $users ) | |
{ | |
Get-ManagerHierarchy -Identity $user.userPrincipalName | |
} | |
# determine the maxium reporting chain depth, needed so we ensure the csv contains the max reporting depth | |
$maxdepth = $results | Measure-Object -Property "ManagerHierarchyDepth" -Maximum | Select-Object -ExpandProperty Maximum | |
# generate static headers for the csv export | |
$headers = "UserPrincipalName", "Department", "JobTitle", "ManagerId" | |
# append "LevelX" header for the maxium depth in our report | |
1..$maxdepth | ForEach-Object -Process { $headers += "Level$($_)" } | |
# timestamp the file | |
$timestamp = Get-Date -Format FileDateTime | |
# export results to csv | |
$results | Select-Object -Property $headers | Export-Csv -Path "UserHierarchy_$timestamp.csv" -NoTypeInformation | |
<# | |
EXAMPLE OUTPUT | |
UserPrincipalName Department JobTitle ManagerId Level1 Level2 Level3 | |
----------------- ---------- -------- --------- ------ ------ ------ | |
[email protected] IT IT Leader [email protected] [email protected] [email protected] [email protected] | |
[email protected] Legal [email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] | |
[email protected] HR Director [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] [email protected] | |
[email protected] CVP HR [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] | |
[email protected] HR Leader [email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] [email protected] | |
[email protected] [email protected] [email protected] [email protected] [email protected] | |
#> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment