Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save win2000b/f6f0e2670e325480a3eae78900f1844b to your computer and use it in GitHub Desktop.

Select an option

Save win2000b/f6f0e2670e325480a3eae78900f1844b to your computer and use it in GitHub Desktop.
Find Manager Subordinates and recurse down
# Run with "powershell -ExecutionPolicy Bypass -File .\Get-EntraSubordinates-WithManagerOnly.ps1"
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "User.Read.All", "Directory.Read.All"
# Function to recursively retrieve all subordinates under a manager
function Get-SubordinatesRecursive {
param (
[string]$ManagerId,
[hashtable]$Visited,
[string]$ManagerName
)
$results = @()
if (-not ($ManagerId -match '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')) {
Write-Warning "Skipping invalid manager ID: $ManagerId"
return $results
}
if ($Visited.ContainsKey($ManagerId)) {
return $results
}
$Visited[$ManagerId] = $true
try {
$directReports = Get-MgUserDirectReport -UserId $ManagerId -All
}
catch {
Write-Warning ("Error retrieving direct reports for manager ID ${ManagerId}: " + $_.Exception.Message)
return $results
}
foreach ($report in $directReports) {
try {
$user = Get-MgUser -UserId $report.Id
$user | Add-Member -NotePropertyName ManagerName -NotePropertyValue $ManagerName
$results += $user
$childResults = Get-SubordinatesRecursive -ManagerId $user.Id -Visited $Visited -ManagerName $user.DisplayName
$results += $childResults
}
catch {
Write-Warning "Could not retrieve user details for $($report.Id): $_"
}
}
return $results
}
# Prompt for the manager
$managerInput = Read-Host "Enter part or all of the manager's Display Name or UPN"
$allUsers = Get-MgUser -All | Select-Object Id, DisplayName, UserPrincipalName
$matchedManagers = $allUsers | Where-Object {
$_.UserPrincipalName -like "*$managerInput*" -or $_.DisplayName -like "*$managerInput*"
}
if ($matchedManagers.Count -eq 0) {
Write-Error "No matching manager found. Please check the input."
return
}
elseif ($matchedManagers.Count -gt 1) {
Write-Output "Multiple matches found:"
$matchedManagers | ForEach-Object -Begin { $i = 0 } -Process {
"$i`t$($_.DisplayName) ($($_.UserPrincipalName))"
$i++
}
$selectedIndex = Read-Host "Enter the index number (0 to $($matchedManagers.Count - 1)) for the correct manager"
if (-not ($selectedIndex -match '^\d+$') -or [int]$selectedIndex -ge $matchedManagers.Count) {
Write-Error "Invalid index. Exiting."
return
}
$manager = $matchedManagers[$selectedIndex]
}
else {
$manager = $matchedManagers[0]
}
if (-not $manager.Id) {
Write-Error "Manager ID is null or empty. Exiting."
return
}
Write-Output "Found top-level manager: $($manager.DisplayName) | ID: $($manager.Id)"
Write-Output "Recursively collecting subordinates..."
$visited = @{}
$allSubordinates = Get-SubordinatesRecursive -ManagerId $manager.Id -Visited $visited -ManagerName $manager.DisplayName
Write-Output "Total subordinates found: $($allSubordinates.Count)"
# Output to console
$allSubordinates | Select-Object DisplayName, UserPrincipalName, ManagerName | Format-Table -AutoSize
# Export to CSV
$csvPath = "Subordinates_With_Manager.csv"
$allSubordinates | Select-Object DisplayName, UserPrincipalName, JobTitle, Department, ManagerName | Export-Csv -Path $csvPath -NoTypeInformation
Write-Output "Results exported to: $csvPath"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment