<# .SYNOPSIS Generates a comprehensive inventory of Azure Service Bus resources across all management groups and subscriptions. .DESCRIPTION This script enumerates all Azure Service Bus namespaces, topics, topic subscriptions, and queues within active subscriptions across the entire Azure tenant. It provides detailed hierarchical mapping of Service Bus messaging infrastructure for monitoring, compliance, and governance reporting. Key capabilities: - Multi-tenant Service Bus discovery across all management groups - Hierarchical messaging structure mapping (namespaces → topics → subscriptions, queues) - Complete Service Bus topology documentation - Management group and subscription context tracking - Resource hierarchy analysis for messaging architecture - Timestamped CSV export for audit trails and capacity planning The script processes the complete Service Bus messaging estate including: - Service Bus namespaces (messaging containers) - Topics (pub/sub messaging endpoints) - Topic subscriptions (message consumers) - Queues (point-to-point messaging endpoints) .PARAMETER None This script does not accept parameters and will process all Service Bus resources across all accessible namespaces. .OUTPUTS CSV File: " azure service bus.csv" Contains columns for: - Resource identification (ID, type, location) - Management hierarchy (management group, subscription, resource group) - Service Bus namespace information - Messaging topology (topic names, subscription names, queue names) .EXAMPLE .\ServiceBus.ps1 Discovers all Service Bus resources and generates: "2024-10-30 1435 azure service bus.csv" .NOTES File Name : ServiceBus.ps1 Author : Cloud Engineering Team Prerequisite : Azure PowerShell modules (Az.ServiceBus, Az.Resources, Az.Accounts) Copyright : (c) 2024 Effectory. All rights reserved. Version History: 1.0 - Initial release with comprehensive Service Bus inventory functionality .LINK https://docs.microsoft.com/en-us/azure/service-bus-messaging/ https://docs.microsoft.com/en-us/powershell/module/az.servicebus/ .COMPONENT Requires Azure PowerShell modules: - Az.ServiceBus (for Service Bus namespace, topic, queue, and subscription enumeration) - Az.Resources (for resource group and management group access) - Az.Accounts (for authentication and subscription management) - Az.Automation (for automation context support) .ROLE Required Azure permissions: - Service Bus Data Reader or higher on all Service Bus namespaces - Management Group Reader for organizational hierarchy access - Reader access on target subscriptions .FUNCTIONALITY - Multi-subscription Service Bus discovery - Messaging topology analysis and hierarchical mapping - Complete Service Bus infrastructure documentation - CSV export with comprehensive messaging architecture details #> #Requires -Modules Az.ServiceBus, Az.Resources, Az.Accounts, Az.Automation #Requires -Version 5.1 [CmdletBinding()] param() # Import required modules Import-Module Az.Accounts Import-Module Az.Automation Import-Module Az.ServiceBus Import-Module Az.Resources class ResourceCheck { [string] $ResourceId = "" [string] $ManagementGroupId = "" [string] $ManagementGroupName = "" [string] $SubscriptionId = "" [string] $SubscriptionName = "" [string] $ResourceGroup = "" [string] $RespourceType = "" [string] $Location = "" [string] $ServiceBusName = "" [string] $TopicName = "" [string] $TopicSubscriptionName = "" [string] $QueueName = "" } # Initialize script execution $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" $startTime = Get-Date Write-Host "======================================================================================================================================================================" Write-Host "🚌 AZURE SERVICE BUS INVENTORY GENERATOR" -ForegroundColor Cyan Write-Host "======================================================================================================================================================================" Write-Host "⏰ Started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Green Write-Host "" try { # Validate Azure authentication $context = Get-AzContext if (-not $context) { throw "No Azure context found. Please run Connect-AzAccount first." } Write-Host "🔐 Authenticated as: $($context.Account.Id)" -ForegroundColor Green Write-Host "đŸĸ Tenant: $($context.Tenant.Id)" -ForegroundColor Green Write-Host "" # Initialize output file and tracking variables [string] $date = Get-Date -Format "yyyy-MM-dd HHmm" $fileName = ".\$date azure service bus.csv" Write-Host "📄 Output file: $fileName" -ForegroundColor Yellow Write-Host "" # Initialize counters for progress tracking $totalNamespaces = 0 $totalTopics = 0 $totalTopicSubscriptions = 0 $totalQueues = 0 $processedManagementGroups = 0 $processedSubscriptions = 0 # Get management groups for organizational structure Write-Host "đŸ—ī¸ Discovering management group structure..." -ForegroundColor Cyan $managementGroups = Get-AzManagementGroup Write-Host "✅ Found $($managementGroups.Count) management groups" -ForegroundColor Green Write-Host "" # Process each management group foreach ($managementGroup in $managementGroups) { $processedManagementGroups++ Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------" Write-Host "đŸ—ī¸ Management Group [$($managementGroup.DisplayName)]" -ForegroundColor Cyan Write-Host " ID: $($managementGroup.Id)" -ForegroundColor DarkGray try { # Get active subscriptions in this management group $subscriptions = Get-AzManagementGroupSubscription -Group $managementGroup.Name | Where-Object State -eq "Active" Write-Host " 📋 Found $($subscriptions.Count) active subscriptions" -ForegroundColor Green foreach ($subscription in $subscriptions) { $processedSubscriptions++ Write-Host "" Write-Host " 🔄 Processing Subscription: $($subscription.DisplayName)" -ForegroundColor Yellow try { # Extract subscription ID and set context $scope = $subscription.Id.Substring($subscription.Parent.Length, $subscription.Id.Length - $subscription.Parent.Length) $subscriptionId = $scope.Replace("/subscriptions/", "") Write-Host " ID: $subscriptionId" -ForegroundColor DarkGray Set-AzContext -SubscriptionId $subscriptionId | Out-Null # Get Service Bus namespaces in the subscription Write-Host " 🔍 Discovering Service Bus namespaces..." -ForegroundColor Cyan $servicebusses = Get-AzServiceBusNamespaceV2 -ErrorAction SilentlyContinue if ($servicebusses.Count -gt 0) { Write-Host " ✅ Found $($servicebusses.Count) Service Bus namespaces" -ForegroundColor Green $totalNamespaces += $servicebusses.Count } else { Write-Host " â„šī¸ No Service Bus namespaces found" -ForegroundColor DarkGray } foreach ($servicebus in $servicebusses) { Write-Host " đŸ“Ļ Processing namespace: $($servicebus.Name)" -ForegroundColor Yellow try { [ResourceCheck[]]$Result = @() $namespaceTopics = 0 $namespaceTopicSubs = 0 $namespaceQueues = 0 # Add namespace entry [ResourceCheck] $resourceCheck = [ResourceCheck]::new() $resourceCheck.ResourceId = $servicebus.Id $resourceCheck.ManagementGroupId = $managementGroup.Id $resourceCheck.ManagementGroupName = $managementGroup.DisplayName $resourceCheck.SubscriptionId = $subscription.Id $resourceCheck.SubscriptionName = $subscription.DisplayName $resourceCheck.ResourceGroup = $servicebus.ResourceGroupName $resourceCheck.RespourceType = $servicebus.Type $resourceCheck.Location = $servicebus.Location $resourceCheck.ServiceBusName = $servicebus.Name $Result += $resourceCheck # Process topics Write-Host " 🔍 Discovering topics..." -ForegroundColor DarkCyan try { $topics = Get-AzServiceBusTopic -NamespaceName $servicebus.Name -ResourceGroupName $servicebus.ResourceGroupName -ErrorAction SilentlyContinue if ($topics.Count -gt 0) { Write-Host " 📊 Found $($topics.Count) topics" -ForegroundColor Green $namespaceTopics = $topics.Count $totalTopics += $topics.Count } else { Write-Host " â„šī¸ No topics found" -ForegroundColor DarkGray } foreach ($topic in $topics) { [ResourceCheck] $resourceCheck = [ResourceCheck]::new() $resourceCheck.ResourceId = $servicebus.Id $resourceCheck.ManagementGroupId = $managementGroup.Id $resourceCheck.ManagementGroupName = $managementGroup.DisplayName $resourceCheck.SubscriptionId = $subscription.Id $resourceCheck.SubscriptionName = $subscription.DisplayName $resourceCheck.ResourceGroup = $servicebus.ResourceGroupName $resourceCheck.RespourceType = $topic.Type $resourceCheck.Location = $servicebus.Location $resourceCheck.ServiceBusName = $servicebus.Name $resourceCheck.TopicName = $topic.Name $Result += $resourceCheck # Process topic subscriptions try { $topicSubs = Get-AzServiceBusSubscription -NamespaceName $servicebus.Name -ResourceGroupName $servicebus.ResourceGroupName -TopicName $topic.Name -ErrorAction SilentlyContinue foreach ($topicSub in $topicSubs) { [ResourceCheck] $resourceCheck = [ResourceCheck]::new() $resourceCheck.ResourceId = $servicebus.Id $resourceCheck.ManagementGroupId = $managementGroup.Id $resourceCheck.ManagementGroupName = $managementGroup.DisplayName $resourceCheck.SubscriptionId = $subscription.Id $resourceCheck.SubscriptionName = $subscription.DisplayName $resourceCheck.ResourceGroup = $servicebus.ResourceGroupName $resourceCheck.RespourceType = $topicSub.Type $resourceCheck.Location = $servicebus.Location $resourceCheck.ServiceBusName = $servicebus.Name $resourceCheck.TopicName = $topic.Name $resourceCheck.TopicSubscriptionName = $topicSub.Name $Result += $resourceCheck $namespaceTopicSubs++ $totalTopicSubscriptions++ } } catch { Write-Host " âš ī¸ Error getting subscriptions for topic '$($topic.Name)': $($_.Exception.Message)" -ForegroundColor Yellow } } } catch { Write-Host " ❌ Error getting topics: $($_.Exception.Message)" -ForegroundColor Red } # Process queues Write-Host " 🔍 Discovering queues..." -ForegroundColor DarkCyan try { $queues = Get-AzServiceBusQueue -NamespaceName $servicebus.Name -ResourceGroupName $servicebus.ResourceGroupName -ErrorAction SilentlyContinue if ($queues.Count -gt 0) { Write-Host " 📊 Found $($queues.Count) queues" -ForegroundColor Green $namespaceQueues = $queues.Count $totalQueues += $queues.Count } else { Write-Host " â„šī¸ No queues found" -ForegroundColor DarkGray } foreach ($queue in $queues) { [ResourceCheck] $resourceCheck = [ResourceCheck]::new() $resourceCheck.ResourceId = $servicebus.Id $resourceCheck.ManagementGroupId = $managementGroup.Id $resourceCheck.ManagementGroupName = $managementGroup.DisplayName $resourceCheck.SubscriptionId = $subscription.Id $resourceCheck.SubscriptionName = $subscription.DisplayName $resourceCheck.ResourceGroup = $servicebus.ResourceGroupName $resourceCheck.RespourceType = $queue.Type $resourceCheck.Location = $servicebus.Location $resourceCheck.ServiceBusName = $servicebus.Name $resourceCheck.QueueName = $queue.Name $Result += $resourceCheck } } catch { Write-Host " ❌ Error getting queues: $($_.Exception.Message)" -ForegroundColor Red } # Export results for this namespace if ($Result.Count -gt 0) { $Result | Export-Csv -Path $fileName -Append -NoTypeInformation Write-Host " ✅ Exported $($Result.Count) Service Bus resources" -ForegroundColor Green Write-Host " Topics: $namespaceTopics, Subscriptions: $namespaceTopicSubs, Queues: $namespaceQueues" -ForegroundColor DarkGray } } catch { Write-Host " ❌ Error processing namespace '$($servicebus.Name)': $($_.Exception.Message)" -ForegroundColor Red } } } catch { Write-Host " ❌ Error processing subscription: $($_.Exception.Message)" -ForegroundColor Red } } } catch { Write-Host " ❌ Error accessing management group: $($_.Exception.Message)" -ForegroundColor Red } Write-Host "" } # Calculate execution time and generate comprehensive summary report $endTime = Get-Date $executionTime = $endTime - $startTime Write-Host "======================================================================================================================================================================" Write-Host "📊 AZURE SERVICE BUS INVENTORY SUMMARY" -ForegroundColor Cyan Write-Host "======================================================================================================================================================================" Write-Host "⏰ Execution Time: $($executionTime.ToString('hh\:mm\:ss'))" -ForegroundColor Green Write-Host "đŸ—ī¸ Management Groups Processed: $processedManagementGroups" -ForegroundColor Green Write-Host "📋 Subscriptions Processed: $processedSubscriptions" -ForegroundColor Green Write-Host "🚌 Service Bus Namespaces: $totalNamespaces" -ForegroundColor Green Write-Host "📡 Topics Discovered: $totalTopics" -ForegroundColor Cyan Write-Host "📨 Topic Subscriptions: $totalTopicSubscriptions" -ForegroundColor Yellow Write-Host "đŸ“Ŧ Queues Discovered: $totalQueues" -ForegroundColor Magenta Write-Host "📄 Results Exported To: $fileName" -ForegroundColor Yellow if (Test-Path $fileName) { $fileSize = (Get-Item $fileName).Length Write-Host "💾 File Size: $([math]::Round($fileSize/1KB, 2)) KB" -ForegroundColor Green } # Calculate messaging topology insights $totalMessagingEndpoints = $totalTopics + $totalQueues $averageTopicsPerNamespace = if ($totalNamespaces -gt 0) { [math]::Round($totalTopics / $totalNamespaces, 1) } else { 0 } $averageQueuesPerNamespace = if ($totalNamespaces -gt 0) { [math]::Round($totalQueues / $totalNamespaces, 1) } else { 0 } $averageSubsPerTopic = if ($totalTopics -gt 0) { [math]::Round($totalTopicSubscriptions / $totalTopics, 1) } else { 0 } if ($totalNamespaces -gt 0) { Write-Host "" Write-Host "📈 MESSAGING TOPOLOGY ANALYSIS:" -ForegroundColor Cyan Write-Host " Total Messaging Endpoints: $totalMessagingEndpoints (Topics + Queues)" -ForegroundColor White Write-Host " Average Topics per Namespace: $averageTopicsPerNamespace" -ForegroundColor White Write-Host " Average Queues per Namespace: $averageQueuesPerNamespace" -ForegroundColor White if ($totalTopics -gt 0) { Write-Host " Average Subscriptions per Topic: $averageSubsPerTopic" -ForegroundColor White } # Provide architecture insights Write-Host "" Write-Host "đŸ—ī¸ ARCHITECTURE INSIGHTS:" -ForegroundColor Cyan if ($totalTopics -gt $totalQueues) { Write-Host " 📡 Pub/Sub Pattern Dominant: More topics ($totalTopics) than queues ($totalQueues)" -ForegroundColor Green Write-Host " This indicates a preference for broadcast messaging patterns" -ForegroundColor White } elseif ($totalQueues -gt $totalTopics) { Write-Host " đŸ“Ŧ Point-to-Point Pattern Dominant: More queues ($totalQueues) than topics ($totalTopics)" -ForegroundColor Green Write-Host " This indicates a preference for direct messaging patterns" -ForegroundColor White } else { Write-Host " âš–ī¸ Balanced Architecture: Equal distribution of topics and queues" -ForegroundColor Green Write-Host " This indicates a mixed messaging architecture approach" -ForegroundColor White } if ($totalTopicSubscriptions -gt ($totalTopics * 2)) { Write-Host " 🔄 High Fan-out: Multiple consumers per topic (avg: $averageSubsPerTopic subscribers)" -ForegroundColor Yellow Write-Host " Consider monitoring subscription performance and message distribution" -ForegroundColor White } } Write-Host "" Write-Host "📈 NEXT STEPS:" -ForegroundColor Cyan Write-Host " 1. Review the generated CSV file for detailed Service Bus topology" -ForegroundColor White Write-Host " 2. Analyze messaging patterns and identify optimization opportunities" -ForegroundColor White Write-Host " 3. Monitor Service Bus performance metrics and throughput" -ForegroundColor White Write-Host " 4. Consider namespace consolidation for cost optimization" -ForegroundColor White Write-Host " 5. Implement message monitoring and alerting for critical endpoints" -ForegroundColor White Write-Host " 6. Review security settings and access policies for each namespace" -ForegroundColor White Write-Host "" Write-Host "✅ Azure Service Bus inventory completed successfully!" -ForegroundColor Green Write-Host "======================================================================================================================================================================" } catch { Write-Host "" Write-Host "❌ CRITICAL ERROR OCCURRED" -ForegroundColor Red Write-Host "======================================================================================================================================================================" Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red Write-Host "Line: $($_.InvocationInfo.ScriptLineNumber)" -ForegroundColor Red Write-Host "Position: $($_.InvocationInfo.OffsetInLine)" -ForegroundColor Red Write-Host "" Write-Host "🔧 TROUBLESHOOTING STEPS:" -ForegroundColor Yellow Write-Host " 1. Verify you are authenticated to Azure (Connect-AzAccount)" -ForegroundColor White Write-Host " 2. Ensure you have Service Bus Data Reader permissions on target namespaces" -ForegroundColor White Write-Host " 3. Check that the Management Group Reader role is assigned" -ForegroundColor White Write-Host " 4. Verify Azure PowerShell modules are installed and up to date" -ForegroundColor White Write-Host " 5. Confirm that Service Bus namespaces are accessible and not deleted" -ForegroundColor White Write-Host " 6. Try running the script with -Verbose for additional diagnostic information" -ForegroundColor White Write-Host "" Write-Host "📞 For additional support, contact the Cloud Engineering team" -ForegroundColor Cyan Write-Host "======================================================================================================================================================================" # Ensure we exit with error code for automation scenarios exit 1 } finally { # Reset progress preference $ProgressPreference = "Continue" }