mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 10:45:02 +01:00
407 lines
23 KiB
PowerShell
407 lines
23 KiB
PowerShell
<#
|
||
.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: "<date> 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"
|
||
}
|
||
|