added documetation

This commit is contained in:
Jurjen Ladenius
2025-11-03 08:12:01 +01:00
parent 8840b0e300
commit a226ca97ac
37 changed files with 8315 additions and 1481 deletions

View File

@@ -1,4 +1,81 @@
#Connect-AzAccount
<#
.SYNOPSIS
Generates a comprehensive inventory of all Azure resources across enabled subscriptions.
.DESCRIPTION
This script enumerates all Azure resources within enabled subscriptions across the entire Azure tenant,
collecting detailed resource properties, governance tags, and managed identity information. The results
are exported to a timestamped CSV file for analysis, compliance reporting, and resource management.
Key capabilities:
- Cross-subscription resource discovery and enumeration
- Comprehensive resource metadata collection (type, location, resource group)
- Governance tag extraction for team ownership and compliance tracking
- Managed identity discovery and principal ID mapping
- Resource lifecycle management tags (delete, split, deployment tracking)
- Timestamped CSV export with complete audit trail
The script processes all enabled subscriptions and captures essential resource information
including resource hierarchy, governance tags, and security identities for comprehensive
Azure estate management and reporting.
.PARAMETER None
This script does not accept parameters and will process all resources in all enabled subscriptions.
.OUTPUTS
CSV File: "<date> Resources.csv"
Contains columns for:
- Resource identification (ID, name, type, kind, location)
- Subscription and resource group context
- Governance tags (team, product, environment, data classification)
- Lifecycle management tags (delete, split, created date, deployment)
- Managed identity information (name, principal ID)
.EXAMPLE
.\Resources.ps1
Discovers all resources across enabled subscriptions and generates:
"2024-10-30 1435 Resources.csv"
.NOTES
File Name : Resources.ps1
Author : Cloud Engineering Team
Prerequisite : Azure PowerShell module (Az.Resources, Az.Accounts, Az.ManagedServiceIdentity)
Copyright : (c) 2024 Effectory. All rights reserved.
Version History:
1.0 - Initial release with comprehensive resource inventory functionality
.LINK
https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/overview
https://docs.microsoft.com/en-us/powershell/module/az.resources/
.COMPONENT
Requires Azure PowerShell modules:
- Az.Resources (for resource enumeration and property retrieval)
- Az.Accounts (for authentication and subscription management)
- Az.ManagedServiceIdentity (for managed identity discovery)
.ROLE
Required Azure permissions:
- Reader or higher on all target subscriptions
- Managed Identity Operator (for identity information retrieval)
.FUNCTIONALITY
- Multi-subscription resource discovery and enumeration
- Governance tag extraction and compliance tracking
- Managed identity mapping and security context analysis
- CSV export with comprehensive resource metadata
#>
#Requires -Modules Az.Resources, Az.Accounts, Az.ManagedServiceIdentity
#Requires -Version 5.1
[CmdletBinding()]
param()
# Uncomment the following line if authentication is required
#Connect-AzAccount
class ResourceCheck {
[string] $ResourceId = ""
@@ -22,59 +99,259 @@ class ResourceCheck {
[string] $ManagedIndentity_PrincipalId = ""
}
Write-Host "========================================================================================================================================================================"
Write-Host "Creating resource overview."
Write-Host "========================================================================================================================================================================"
# Initialize script execution
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
$startTime = Get-Date
$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
Write-Host "======================================================================================================================================================================"
Write-Host "🔍 AZURE RESOURCE INVENTORY GENERATOR" -ForegroundColor Cyan
Write-Host "======================================================================================================================================================================"
Write-Host "⏰ Started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Green
Write-Host ""
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
$fileName = ".\$date Resources.csv"
foreach ($subscription in $subscriptions)
{
Set-AzContext -SubscriptionId $subscription.Id
$allResources = Get-AzResource
[ResourceCheck[]]$Result = @()
try {
# Validate Azure authentication
$context = Get-AzContext
if (-not $context) {
throw "No Azure context found. Please run Connect-AzAccount first."
}
foreach ($resource in $allResources)
{
[ResourceCheck] $resourceCheck = [ResourceCheck]::new()
$resourceCheck.ResourceId = $resource.ResourceId
$resourceCheck.Id = $resource.Id
$resourceCheck.Kind = $resource.Kind
$resourceCheck.Location = $resource.Location
$resourceCheck.ResourceName = $resource.ResourceName
$resourceCheck.ResourceGroupName = $resource.ResourceGroupName
$resourceCheck.ResourceType = $resource.ResourceType
$resourceCheck.SubscriptionId = $subscription.Id
$resourceCheck.SubscriptionName = $subscription.Name
$resourceCheck.Tag_Team = $resource.Tags.team
$resourceCheck.Tag_Product = $resource.Tags.product
$resourceCheck.Tag_Environment = $resource.Tags.environment
$resourceCheck.Tag_Data = $resource.Tags.data
$resourceCheck.Tag_Delete = $resource.Tags.delete
$resourceCheck.Tag_Split = $resource.Tags.split
$resourceCheck.Tag_CreatedOnDate = $resource.Tags.CreatedOnDate
$resourceCheck.Tag_Deployment = $resource.Tags.drp_deployment
Write-Host "🔐 Authenticated as: $($context.Account.Id)" -ForegroundColor Green
Write-Host "🏢 Tenant: $($context.Tenant.Id)" -ForegroundColor Green
Write-Host ""
# Get enabled subscriptions
Write-Host "🔄 Discovering enabled subscriptions..." -ForegroundColor Cyan
$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
Write-Host "✅ Found $($subscriptions.Count) enabled subscriptions" -ForegroundColor Green
Write-Host ""
# Initialize output file and tracking variables
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
$fileName = ".\$date Resources.csv"
Write-Host "📄 Output file: $fileName" -ForegroundColor Yellow
Write-Host ""
$totalResources = 0
$processedSubscriptions = 0
$resourceTypes = @{}
$managedIdentityCount = 0
$governanceIssues = @()
# Process each subscription
foreach ($subscription in $subscriptions) {
$processedSubscriptions++
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
Write-Host "🔄 Processing Subscription [$($processedSubscriptions)/$($subscriptions.Count)]: $($subscription.Name)" -ForegroundColor Yellow
Write-Host " ID: $($subscription.Id)" -ForegroundColor DarkGray
try {
$managedIdentity = $null
$managedIdentity = Get-AzSystemAssignedIdentity -Scope $resource.ResourceId -erroraction 'silentlycontinue'
$resourceCheck.ManagedIndentity_Name = $managedIdentity.Name
$resourceCheck.ManagedIndentity_PrincipalId = $managedIdentity.PrincipalId
}
catch {
$resourceCheck.ManagedIndentity_Name = ""
$resourceCheck.ManagedIndentity_PrincipalId = ""
}
Set-AzContext -SubscriptionId $subscription.Id | Out-Null
$Result += $resourceCheck
# Get all resources in the subscription
Write-Host " 🔍 Discovering resources..." -ForegroundColor Cyan
$allResources = Get-AzResource -ErrorAction Stop
Write-Host " ✅ Found $($allResources.Count) resources" -ForegroundColor Green
[ResourceCheck[]]$Result = @()
$subscriptionResourceCount = 0
$subscriptionManagedIdentityCount = 0
foreach ($resource in $allResources) {
try {
$subscriptionResourceCount++
# Track resource types for analytics
if ($resourceTypes.ContainsKey($resource.ResourceType)) {
$resourceTypes[$resource.ResourceType]++
} else {
$resourceTypes[$resource.ResourceType] = 1
}
# Create resource check object
[ResourceCheck] $resourceCheck = [ResourceCheck]::new()
$resourceCheck.ResourceId = $resource.ResourceId
$resourceCheck.Id = $resource.Id
$resourceCheck.Kind = $resource.Kind
$resourceCheck.Location = $resource.Location
$resourceCheck.ResourceName = $resource.ResourceName
$resourceCheck.ResourceGroupName = $resource.ResourceGroupName
$resourceCheck.ResourceType = $resource.ResourceType
$resourceCheck.SubscriptionId = $subscription.Id
$resourceCheck.SubscriptionName = $subscription.Name
$resourceCheck.Tag_Team = $resource.Tags.team
$resourceCheck.Tag_Product = $resource.Tags.product
$resourceCheck.Tag_Environment = $resource.Tags.environment
$resourceCheck.Tag_Data = $resource.Tags.data
$resourceCheck.Tag_Delete = $resource.Tags.delete
$resourceCheck.Tag_Split = $resource.Tags.split
$resourceCheck.Tag_CreatedOnDate = $resource.Tags.CreatedOnDate
$resourceCheck.Tag_Deployment = $resource.Tags.drp_deployment
# Check for governance tag compliance
$missingTags = @()
if ([string]::IsNullOrEmpty($resource.Tags.team)) { $missingTags += "team" }
if ([string]::IsNullOrEmpty($resource.Tags.product)) { $missingTags += "product" }
if ([string]::IsNullOrEmpty($resource.Tags.environment)) { $missingTags += "environment" }
if ($missingTags.Count -gt 0) {
$governanceIssues += "⚠️ Missing tags [$($missingTags -join ', ')] on $($resource.ResourceType): $($resource.ResourceName) in $($resource.ResourceGroupName)"
}
# Attempt to get managed identity information
try {
$managedIdentity = Get-AzSystemAssignedIdentity -Scope $resource.ResourceId -ErrorAction SilentlyContinue
if ($managedIdentity) {
$resourceCheck.ManagedIndentity_Name = $managedIdentity.Name
$resourceCheck.ManagedIndentity_PrincipalId = $managedIdentity.PrincipalId
$subscriptionManagedIdentityCount++
$managedIdentityCount++
} else {
$resourceCheck.ManagedIndentity_Name = ""
$resourceCheck.ManagedIndentity_PrincipalId = ""
}
} catch {
# Silently handle managed identity lookup failures
$resourceCheck.ManagedIndentity_Name = ""
$resourceCheck.ManagedIndentity_PrincipalId = ""
}
$Result += $resourceCheck
$totalResources++
# Show progress for large subscriptions
if ($subscriptionResourceCount % 100 -eq 0) {
Write-Host " 📊 Processed $subscriptionResourceCount resources..." -ForegroundColor DarkCyan
}
} catch {
Write-Host " ❌ Error processing resource '$($resource.ResourceName)': $($_.Exception.Message)" -ForegroundColor Red
}
}
# Export results for this subscription
if ($Result.Count -gt 0) {
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
Write-Host " ✅ Exported $($Result.Count) resources" -ForegroundColor Green
if ($subscriptionManagedIdentityCount -gt 0) {
Write-Host " 🔐 Found $subscriptionManagedIdentityCount managed identities" -ForegroundColor Cyan
}
} else {
Write-Host " No resources found in subscription" -ForegroundColor DarkYellow
}
} catch {
Write-Host " ❌ Error processing subscription: $($_.Exception.Message)" -ForegroundColor Red
}
Write-Host ""
}
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
}
# Calculate execution time and generate comprehensive summary report
$endTime = Get-Date
$executionTime = $endTime - $startTime
Write-Host "========================================================================================================================================================================"
Write-Host "Done."
Write-Host "======================================================================================================================================================================"
Write-Host "📊 AZURE RESOURCE INVENTORY SUMMARY" -ForegroundColor Cyan
Write-Host "======================================================================================================================================================================"
Write-Host "⏰ Execution Time: $($executionTime.ToString('hh\:mm\:ss'))" -ForegroundColor Green
Write-Host "📋 Subscriptions Processed: $processedSubscriptions" -ForegroundColor Green
Write-Host "🔍 Total Resources Discovered: $totalResources" -ForegroundColor Green
Write-Host "🔐 Managed Identities Found: $managedIdentityCount" -ForegroundColor Cyan
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
}
# Display top resource types
if ($resourceTypes.Count -gt 0) {
Write-Host ""
Write-Host "📈 TOP RESOURCE TYPES:" -ForegroundColor Cyan
$topResourceTypes = $resourceTypes.GetEnumerator() | Sort-Object Value -Descending | Select-Object -First 10
foreach ($resourceType in $topResourceTypes) {
Write-Host " $($resourceType.Key): $($resourceType.Value) resources" -ForegroundColor White
}
if ($resourceTypes.Count -gt 10) {
$remainingTypes = $resourceTypes.Count - 10
$remainingResources = ($resourceTypes.GetEnumerator() | Sort-Object Value -Descending | Select-Object -Skip 10 | Measure-Object Value -Sum).Sum
Write-Host " ... and $remainingTypes more types ($remainingResources resources)" -ForegroundColor DarkGray
}
}
# Display governance analysis
if ($governanceIssues.Count -gt 0) {
Write-Host ""
Write-Host "🚨 GOVERNANCE ANALYSIS" -ForegroundColor Red
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
Write-Host "Found $($governanceIssues.Count) resources with missing governance tags:" -ForegroundColor Yellow
foreach ($issue in $governanceIssues | Select-Object -First 15) {
Write-Host " $issue" -ForegroundColor Yellow
}
if ($governanceIssues.Count -gt 15) {
Write-Host " ... and $($governanceIssues.Count - 15) more governance issues (see CSV for complete details)" -ForegroundColor DarkYellow
}
Write-Host ""
Write-Host "📋 Governance Recommendations:" -ForegroundColor Cyan
Write-Host " • Implement mandatory tagging policies for team, product, and environment" -ForegroundColor White
Write-Host " • Use Azure Policy to enforce governance tag compliance" -ForegroundColor White
Write-Host " • Establish resource naming conventions and tagging standards" -ForegroundColor White
Write-Host " • Regular governance audits using this resource inventory" -ForegroundColor White
} else {
Write-Host ""
Write-Host "✅ GOVERNANCE ANALYSIS: All resources have required governance tags" -ForegroundColor Green
}
# Security and identity insights
if ($managedIdentityCount -gt 0) {
$identityPercentage = [math]::Round(($managedIdentityCount / $totalResources) * 100, 1)
Write-Host ""
Write-Host "🔐 SECURITY ANALYSIS:" -ForegroundColor Cyan
Write-Host " Managed Identity Adoption: $identityPercentage% of resources ($managedIdentityCount/$totalResources)" -ForegroundColor Green
Write-Host " 💡 Consider expanding managed identity usage for enhanced security" -ForegroundColor White
}
Write-Host ""
Write-Host "📈 NEXT STEPS:" -ForegroundColor Cyan
Write-Host " 1. Review the generated CSV file for detailed resource analysis" -ForegroundColor White
Write-Host " 2. Address governance tag compliance issues identified above" -ForegroundColor White
Write-Host " 3. Analyze resource distribution across subscriptions and regions" -ForegroundColor White
Write-Host " 4. Consider resource optimization opportunities (unused resources, right-sizing)" -ForegroundColor White
Write-Host " 5. Implement automated resource monitoring and cost management" -ForegroundColor White
Write-Host " 6. Use managed identity information for security auditing" -ForegroundColor White
Write-Host ""
Write-Host "✅ Azure resource 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 Reader permissions on all target subscriptions" -ForegroundColor White
Write-Host " 3. Check that Azure PowerShell modules are installed and up to date" -ForegroundColor White
Write-Host " 4. Verify Managed Identity Operator role for identity information retrieval" -ForegroundColor White
Write-Host " 5. Try running the script with -Verbose for additional diagnostic information" -ForegroundColor White
Write-Host " 6. Consider processing subscriptions individually if encountering timeout issues" -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"
}