updated management groups overview with extra levels for the cost overview #125630

This commit is contained in:
Jurjen Ladenius
2025-12-19 10:41:15 +01:00
parent e30af22220
commit 0212b4b98b

View File

@@ -5,7 +5,7 @@
.DESCRIPTION .DESCRIPTION
This script creates a comprehensive mapping of Azure organizational structure by traversing This script creates a comprehensive mapping of Azure organizational structure by traversing
the management group hierarchy starting from a specified root management group. It discovers the management group hierarchy starting from a specified root management group. It discovers
and documents all subscriptions within a 3-level management group structure (Level 0-2). and documents all subscriptions within a 5-level management group structure (Level 0-4).
The script provides detailed organizational visibility including: The script provides detailed organizational visibility including:
- Hierarchical management group structure mapping - Hierarchical management group structure mapping
@@ -14,7 +14,7 @@
- Multi-level governance structure documentation - Multi-level governance structure documentation
- CSV export for organizational analysis and compliance reporting - CSV export for organizational analysis and compliance reporting
Note: The script is optimized for a maximum 3-level management group depth and starts Note: The script is optimized for a maximum 5-level management group depth and starts
from a configurable root management group ID. from a configurable root management group ID.
.PARAMETER RootManagementGroupId .PARAMETER RootManagementGroupId
@@ -30,6 +30,8 @@
- Level 0 Management Group (root level) - Level 0 Management Group (root level)
- Level 1 Management Group (department/division level) - Level 1 Management Group (department/division level)
- Level 2 Management Group (team/project level) - Level 2 Management Group (team/project level)
- Level 3 Management Group (workload/application level)
- Level 4 Management Group (environment/instance level)
.EXAMPLE .EXAMPLE
.\ManagementGroups.ps1 .\ManagementGroups.ps1
@@ -56,6 +58,8 @@
Version History: Version History:
1.0 - Initial release with 3-level management group hierarchy discovery 1.0 - Initial release with 3-level management group hierarchy discovery
1.1 - Added parameterized root management group for flexibility 1.1 - Added parameterized root management group for flexibility
1.2 - Extended to 4-level management group hierarchy (added Level 3)
1.3 - Extended to 5-level management group hierarchy (added Level 4)
.LINK .LINK
https://docs.microsoft.com/en-us/azure/governance/management-groups/ https://docs.microsoft.com/en-us/azure/governance/management-groups/
@@ -72,7 +76,7 @@
- Reader access to view subscription details within management groups - Reader access to view subscription details within management groups
.FUNCTIONALITY .FUNCTIONALITY
- Hierarchical management group discovery (3-level maximum) - Hierarchical management group discovery (5-level maximum)
- Subscription placement mapping and state tracking - Subscription placement mapping and state tracking
- Organizational structure documentation and CSV export - Organizational structure documentation and CSV export
- Cross-tenant compatible with configurable root management group - Cross-tenant compatible with configurable root management group
@@ -101,9 +105,13 @@ class ResourceCheck {
[string] $Level0_ManagementGroupId = "" [string] $Level0_ManagementGroupId = ""
[string] $Level1_ManagementGroupId = "" [string] $Level1_ManagementGroupId = ""
[string] $Level2_ManagementGroupId = "" [string] $Level2_ManagementGroupId = ""
[string] $Level3_ManagementGroupId = ""
[string] $Level4_ManagementGroupId = ""
[string] $Level0_ManagementGroupName = "" [string] $Level0_ManagementGroupName = ""
[string] $Level1_ManagementGroupName = "" [string] $Level1_ManagementGroupName = ""
[string] $Level2_ManagementGroupName = "" [string] $Level2_ManagementGroupName = ""
[string] $Level3_ManagementGroupName = ""
[string] $Level4_ManagementGroupName = ""
} }
# Initialize script execution # Initialize script execution
@@ -294,6 +302,132 @@ try {
} }
} }
# Process Level 3 management groups (nested within Level 2)
$level3Groups = $level2ManagementGroup.Children | Where-Object Type -EQ 'Microsoft.Management/managementGroups'
if ($level3Groups.Count -gt 0) {
Write-Host " 🔍 Found $($level3Groups.Count) Level 3 management groups" -ForegroundColor Green
foreach ($level3ManagementGroupLister in $level3Groups) {
try {
$managementGroupCount++
$level3ManagementGroup = Get-AzManagementGroup -Group $level3ManagementGroupLister.Name -Expand -ErrorAction Stop
Write-Host ""
Write-Host " ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"
Write-Host " 📁 LEVEL 3: $($level3ManagementGroup.DisplayName)" -ForegroundColor DarkCyan
Write-Host " ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"
$subscriptions = $level3ManagementGroup.Children | Where-Object Type -EQ '/subscriptions'
Write-Host " 📊 Direct subscriptions: $($subscriptions.Count)" -ForegroundColor Green
foreach ($subscription in $subscriptions) {
try {
$scope = $subscription.Id.Substring($subscription.Parent.Length, $subscription.Id.Length - $subscription.Parent.Length)
$subscriptionId = $scope.Replace("/subscriptions/", "")
# Color code subscription state
$stateColor = switch ($subscription.State) {
"Enabled" { "Green" }
"Disabled" { "Red" }
"Warned" { "Yellow" }
default { "White" }
}
Write-Host " 📋 Subscription: $($subscription.DisplayName) [$subscriptionId] - $($subscription.State)" -ForegroundColor $stateColor
[ResourceCheck] $resourceCheck = [ResourceCheck]::new()
$resourceCheck.Level0_ManagementGroupId = $rootManagementGroup.Id
$resourceCheck.Level0_ManagementGroupName = $rootManagementGroup.DisplayName
$resourceCheck.Level1_ManagementGroupId = $level1ManagementGroup.Id
$resourceCheck.Level1_ManagementGroupName = $level1ManagementGroup.DisplayName
$resourceCheck.Level2_ManagementGroupId = $level2ManagementGroup.Id
$resourceCheck.Level2_ManagementGroupName = $level2ManagementGroup.DisplayName
$resourceCheck.Level3_ManagementGroupId = $level3ManagementGroup.Id
$resourceCheck.Level3_ManagementGroupName = $level3ManagementGroup.DisplayName
$resourceCheck.SubscriptionId = $subscriptionId
$resourceCheck.SubscriptionName = $subscription.DisplayName
$resourceCheck.SubscriptionState = $subscription.State
$Result += $resourceCheck
$totalSubscriptions++
} catch {
Write-Host " ❌ Error processing subscription: $($_.Exception.Message)" -ForegroundColor Red
}
}
# Process Level 4 management groups (nested within Level 3)
$level4Groups = $level3ManagementGroup.Children | Where-Object Type -EQ 'Microsoft.Management/managementGroups'
if ($level4Groups.Count -gt 0) {
Write-Host " 🔍 Found $($level4Groups.Count) Level 4 management groups" -ForegroundColor Green
foreach ($level4ManagementGroupLister in $level4Groups) {
try {
$managementGroupCount++
$level4ManagementGroup = Get-AzManagementGroup -Group $level4ManagementGroupLister.Name -Expand -ErrorAction Stop
Write-Host ""
Write-Host " ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"
Write-Host " 📂 LEVEL 4: $($level4ManagementGroup.DisplayName)" -ForegroundColor Blue
Write-Host " ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"
$subscriptions = $level4ManagementGroup.Children | Where-Object Type -EQ '/subscriptions'
Write-Host " 📊 Direct subscriptions: $($subscriptions.Count)" -ForegroundColor Green
foreach ($subscription in $subscriptions) {
try {
$scope = $subscription.Id.Substring($subscription.Parent.Length, $subscription.Id.Length - $subscription.Parent.Length)
$subscriptionId = $scope.Replace("/subscriptions/", "")
# Color code subscription state
$stateColor = switch ($subscription.State) {
"Enabled" { "Green" }
"Disabled" { "Red" }
"Warned" { "Yellow" }
default { "White" }
}
Write-Host " 📋 Subscription: $($subscription.DisplayName) [$subscriptionId] - $($subscription.State)" -ForegroundColor $stateColor
[ResourceCheck] $resourceCheck = [ResourceCheck]::new()
$resourceCheck.Level0_ManagementGroupId = $rootManagementGroup.Id
$resourceCheck.Level0_ManagementGroupName = $rootManagementGroup.DisplayName
$resourceCheck.Level1_ManagementGroupId = $level1ManagementGroup.Id
$resourceCheck.Level1_ManagementGroupName = $level1ManagementGroup.DisplayName
$resourceCheck.Level2_ManagementGroupId = $level2ManagementGroup.Id
$resourceCheck.Level2_ManagementGroupName = $level2ManagementGroup.DisplayName
$resourceCheck.Level3_ManagementGroupId = $level3ManagementGroup.Id
$resourceCheck.Level3_ManagementGroupName = $level3ManagementGroup.DisplayName
$resourceCheck.Level4_ManagementGroupId = $level4ManagementGroup.Id
$resourceCheck.Level4_ManagementGroupName = $level4ManagementGroup.DisplayName
$resourceCheck.SubscriptionId = $subscriptionId
$resourceCheck.SubscriptionName = $subscription.DisplayName
$resourceCheck.SubscriptionState = $subscription.State
$Result += $resourceCheck
$totalSubscriptions++
} catch {
Write-Host " ❌ Error processing subscription: $($_.Exception.Message)" -ForegroundColor Red
}
}
} catch {
Write-Host " ❌ Error accessing Level 4 management group '$($level4ManagementGroupLister.Name)': $($_.Exception.Message)" -ForegroundColor Red
}
}
} else {
Write-Host " No Level 4 management groups found" -ForegroundColor DarkGray
}
} catch {
Write-Host " ❌ Error accessing Level 3 management group '$($level3ManagementGroupLister.Name)': $($_.Exception.Message)" -ForegroundColor Red
}
}
} else {
Write-Host " No Level 3 management groups found" -ForegroundColor DarkGray
}
} catch { } catch {
Write-Host " ❌ Error accessing Level 2 management group '$($level2ManagementGroupLister.Name)': $($_.Exception.Message)" -ForegroundColor Red Write-Host " ❌ Error accessing Level 2 management group '$($level2ManagementGroupLister.Name)': $($_.Exception.Message)" -ForegroundColor Red
} }
@@ -345,13 +479,17 @@ try {
# Provide organizational insights # Provide organizational insights
$level0Subs = ($Result | Where-Object { [string]::IsNullOrEmpty($_.Level1_ManagementGroupId) }).Count $level0Subs = ($Result | Where-Object { [string]::IsNullOrEmpty($_.Level1_ManagementGroupId) }).Count
$level1Subs = ($Result | Where-Object { -not [string]::IsNullOrEmpty($_.Level1_ManagementGroupId) -and [string]::IsNullOrEmpty($_.Level2_ManagementGroupId) }).Count $level1Subs = ($Result | Where-Object { -not [string]::IsNullOrEmpty($_.Level1_ManagementGroupId) -and [string]::IsNullOrEmpty($_.Level2_ManagementGroupId) }).Count
$level2Subs = ($Result | Where-Object { -not [string]::IsNullOrEmpty($_.Level2_ManagementGroupId) }).Count $level2Subs = ($Result | Where-Object { -not [string]::IsNullOrEmpty($_.Level2_ManagementGroupId) -and [string]::IsNullOrEmpty($_.Level3_ManagementGroupId) }).Count
$level3Subs = ($Result | Where-Object { -not [string]::IsNullOrEmpty($_.Level3_ManagementGroupId) -and [string]::IsNullOrEmpty($_.Level4_ManagementGroupId) }).Count
$level4Subs = ($Result | Where-Object { -not [string]::IsNullOrEmpty($_.Level4_ManagementGroupId) }).Count
Write-Host "" Write-Host ""
Write-Host "🏗️ ORGANIZATIONAL STRUCTURE:" -ForegroundColor Cyan Write-Host "🏗️ ORGANIZATIONAL STRUCTURE:" -ForegroundColor Cyan
Write-Host " Root Level (Level 0): $level0Subs subscriptions" -ForegroundColor Green Write-Host " Root Level (Level 0): $level0Subs subscriptions" -ForegroundColor Green
Write-Host " Department/Division Level (Level 1): $level1Subs subscriptions" -ForegroundColor Yellow Write-Host " Department/Division Level (Level 1): $level1Subs subscriptions" -ForegroundColor Yellow
Write-Host " Team/Project Level (Level 2): $level2Subs subscriptions" -ForegroundColor Magenta Write-Host " Team/Project Level (Level 2): $level2Subs subscriptions" -ForegroundColor Magenta
Write-Host " Workload/Application Level (Level 3): $level3Subs subscriptions" -ForegroundColor DarkCyan
Write-Host " Environment/Instance Level (Level 4): $level4Subs subscriptions" -ForegroundColor Blue
Write-Host "" Write-Host ""
Write-Host "📈 NEXT STEPS:" -ForegroundColor Cyan Write-Host "📈 NEXT STEPS:" -ForegroundColor Cyan