<# .SYNOPSIS Exports detailed information about Azure Application Insights resources across all enabled subscriptions. .DESCRIPTION This script analyzes all Application Insights resources across enabled Azure subscriptions and collects comprehensive information including: - Basic resource metadata (ID, name, resource group, subscription) - Log Analytics workspace associations - Resource tags for governance and organization The script is particularly useful for: - Application Insights inventory and governance - Monitoring workspace associations for centralized logging - Tag compliance auditing - Cost management and resource organization .PARAMETER SubscriptionFilter Optional array of subscription IDs to analyze. If not specified, all enabled subscriptions are processed. .PARAMETER OutputPath Custom path for the output CSV file. If not specified, creates a timestamped file in the current directory. .EXAMPLE .\AppInsightsWorkspace.ps1 Analyzes all Application Insights resources across all enabled subscriptions. .EXAMPLE .\AppInsightsWorkspace.ps1 -SubscriptionFilter @("12345678-1234-1234-1234-123456789012", "87654321-4321-4321-4321-210987654321") Analyzes Application Insights resources in specific subscriptions only. .EXAMPLE .\AppInsightsWorkspace.ps1 -OutputPath "C:\Reports\appinsights-analysis.csv" Analyzes all Application Insights resources and saves to a custom location. .OUTPUTS Creates a CSV file with the following columns: - SubscriptionId: Azure subscription unique identifier - SubscriptionName: Azure subscription display name - Id: Application Insights resource ID - ResourceGroupName: Resource group containing the Application Insights resource - Name: Application Insights resource name - WorkspaceResourceId: Associated Log Analytics workspace resource ID (if any) - Tag_Team: Value of 'team' tag - Tag_Product: Value of 'product' tag - Tag_Environment: Value of 'environment' tag - Tag_Data: Value of 'data' tag - Tag_CreatedOnDate: Value of 'CreatedOnDate' tag - Tag_Deployment: Value of 'drp_deployment' tag Also displays a formatted table of results in the console. .NOTES Author: Cloud Engineering Team Created: 2025 Requires: PowerShell 5.1 or later, Az PowerShell module Dependencies: Az.ApplicationInsights, Az.Accounts, Az.Resources modules Prerequisites: - Install Az PowerShell module: Install-Module -Name Az - Connect to Azure: Connect-AzAccount - Appropriate permissions to read Application Insights resources across target subscriptions Performance Considerations: - Processing time depends on the number of subscriptions and Application Insights resources - The script switches contexts between subscriptions, which may take time with many subscriptions - Large numbers of resources may result in longer execution times Tag Analysis: The script looks for specific tags commonly used for governance: - team: Identifies the responsible team - product: Associates the resource with a product or service - environment: Indicates the environment (dev, test, prod, etc.) - data: Data classification or sensitivity level - CreatedOnDate: Resource creation timestamp - drp_deployment: Deployment-related information Workspace Association: - Modern Application Insights resources should be associated with Log Analytics workspaces - Resources without workspace associations may be using legacy standalone mode - Workspace associations enable advanced querying and cross-resource analytics .LINK https://docs.microsoft.com/en-us/powershell/module/az.applicationinsights/ https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview #> param( [Parameter(Mandatory = $false, HelpMessage = "Array of subscription IDs to analyze (analyzes all enabled subscriptions if not specified)")] [string[]]$SubscriptionFilter = @(), [Parameter(Mandatory = $false, HelpMessage = "Custom path for the output CSV file")] [string]$OutputPath = "" ) # Check Azure PowerShell authentication Write-Host "Verifying Azure PowerShell authentication..." -ForegroundColor Yellow try { $azContext = Get-AzContext if (-not $azContext) { Write-Host "Not authenticated to Azure. Attempting to connect..." -ForegroundColor Yellow Connect-AzAccount $azContext = Get-AzContext } Write-Host "Azure authentication verified - Account: $($azContext.Account.Id)" -ForegroundColor Green } catch { Write-Host "ERROR: Unable to authenticate to Azure. Please run 'Connect-AzAccount' manually." -ForegroundColor Red exit 1 } # Generate filename if not provided if (-not $OutputPath) { [string] $date = Get-Date -Format "yyyy-MM-dd HHmm" $OutputPath = ".\$date appinsights.csv" } # Get target subscriptions based on filter or all enabled subscriptions Write-Host "Retrieving target subscriptions..." -ForegroundColor Yellow if ($SubscriptionFilter.Count -gt 0) { $subscriptions = $SubscriptionFilter | ForEach-Object { Get-AzSubscription -SubscriptionId $_ | Where-Object State -eq "Enabled" } | Where-Object { $_ -ne $null } Write-Host "Analyzing $($subscriptions.Count) filtered subscriptions" -ForegroundColor Green } else { $subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled" Write-Host "Analyzing all $($subscriptions.Count) enabled subscriptions" -ForegroundColor Green } # Define a class to structure Application Insights resource information class AppInsightsCheck { [string] $SubscriptionId = "" # Azure subscription unique identifier [string] $SubscriptionName = "" # Azure subscription display name [string] $Id = "" # Application Insights resource ID [string] $ResourceGroupName = "" # Resource group containing the resource [string] $Name = "" # Application Insights resource name [string] $WorkspaceResourceId = "" # Associated Log Analytics workspace resource ID [string] $Tag_Team = "" # Team responsible for the resource [string] $Tag_Product = "" # Product or service association [string] $Tag_Environment = "" # Environment designation (dev, test, prod) [string] $Tag_Data = "" # Data classification or sensitivity level [string] $Tag_CreatedOnDate = "" # Resource creation date from tags [string] $Tag_Deployment = "" # Deployment-related information } # Initialize array to store Application Insights analysis results [AppInsightsCheck[]]$Result = @() $totalResourcesProcessed = 0 # Display analysis banner Write-Host "`n========================================================================================================================================================================" Write-Host "AZURE APPLICATION INSIGHTS ANALYSIS" Write-Host "========================================================================================================================================================================" # Process each subscription to analyze Application Insights resources foreach ($subscription in $subscriptions) { Write-Host "`nAnalyzing subscription: $($subscription.Name) ($($subscription.Id))" -ForegroundColor Cyan try { # Switch to the current subscription context Set-AzContext -SubscriptionId $subscription.Id -ErrorAction Stop | Out-Null # Get all Application Insights resources in the subscription Write-Host " Retrieving Application Insights resources..." -ForegroundColor Gray $allAppinsights = Get-AzApplicationInsights -ErrorAction Stop if ($allAppinsights.Count -eq 0) { Write-Host " No Application Insights resources found" -ForegroundColor Yellow continue } Write-Host " Found $($allAppinsights.Count) Application Insights resources" -ForegroundColor Green # Process each Application Insights resource foreach ($appinsights in $allAppinsights) { Write-Host " Processing: $($appinsights.Name)" -ForegroundColor Gray try { # Create new analysis object and populate basic information [AppInsightsCheck] $AppInsightsCheck = [AppInsightsCheck]::new() $AppInsightsCheck.SubscriptionId = $subscription.Id $AppInsightsCheck.SubscriptionName = $subscription.Name $AppInsightsCheck.Id = $appinsights.Id $AppInsightsCheck.Name = $appinsights.Name $AppInsightsCheck.ResourceGroupName = $appinsights.ResourceGroupName $AppInsightsCheck.WorkspaceResourceId = $appinsights.WorkspaceResourceId # Check workspace association if ($appinsights.WorkspaceResourceId) { Write-Host " Workspace-based Application Insights" -ForegroundColor Green } else { Write-Host " Legacy standalone Application Insights (consider migrating)" -ForegroundColor Yellow } # Retrieve detailed resource information for tags Write-Host " Retrieving resource tags..." -ForegroundColor Gray $resource = Get-AzResource -ResourceId $appinsights.Id -ErrorAction Stop # Extract governance tags $AppInsightsCheck.Tag_Team = $resource.Tags.team $AppInsightsCheck.Tag_Product = $resource.Tags.product $AppInsightsCheck.Tag_Environment = $resource.Tags.environment $AppInsightsCheck.Tag_Data = $resource.Tags.data $AppInsightsCheck.Tag_CreatedOnDate = $resource.Tags.CreatedOnDate $AppInsightsCheck.Tag_Deployment = $resource.Tags.drp_deployment # Report on tag compliance $tagCount = @($AppInsightsCheck.Tag_Team, $AppInsightsCheck.Tag_Product, $AppInsightsCheck.Tag_Environment) | Where-Object { $_ } | Measure-Object | Select-Object -ExpandProperty Count if ($tagCount -eq 3) { Write-Host " All required tags present" -ForegroundColor Green } else { Write-Host " Missing required tags (team, product, environment)" -ForegroundColor Yellow } # Add to results $Result += $AppInsightsCheck $totalResourcesProcessed++ } catch { Write-Host " ERROR processing resource: $($_.Exception.Message)" -ForegroundColor Red # Still add basic info even if tag retrieval fails [AppInsightsCheck] $AppInsightsCheck = [AppInsightsCheck]::new() $AppInsightsCheck.SubscriptionId = $subscription.Id $AppInsightsCheck.SubscriptionName = $subscription.Name $AppInsightsCheck.Id = $appinsights.Id $AppInsightsCheck.Name = $appinsights.Name $AppInsightsCheck.ResourceGroupName = $appinsights.ResourceGroupName $AppInsightsCheck.WorkspaceResourceId = $appinsights.WorkspaceResourceId $Result += $AppInsightsCheck $totalResourcesProcessed++ } } } catch { Write-Host " ERROR accessing subscription: $($_.Exception.Message)" -ForegroundColor Red continue } } # Export results to CSV file Write-Host "`nExporting results to: $OutputPath" -ForegroundColor Yellow $Result | Export-Csv -Path $OutputPath -NoTypeInformation -Force # Calculate and display summary statistics $totalSubscriptions = $subscriptions.Count $workspaceBasedCount = ($Result | Where-Object { $_.WorkspaceResourceId -ne "" }).Count $legacyCount = ($Result | Where-Object { $_.WorkspaceResourceId -eq "" }).Count $taggedResourcesCount = ($Result | Where-Object { $_.Tag_Team -ne "" -and $_.Tag_Product -ne "" -and $_.Tag_Environment -ne "" }).Count # Display completion summary Write-Host "`n========================================================================================================================================================================" Write-Host "APPLICATION INSIGHTS ANALYSIS COMPLETED SUCCESSFULLY!" -ForegroundColor Green Write-Host "========================================================================================================================================================================" Write-Host "" Write-Host "SUMMARY STATISTICS:" -ForegroundColor Cyan Write-Host "Subscriptions analyzed: $totalSubscriptions" -ForegroundColor Yellow Write-Host "Total Application Insights resources: $totalResourcesProcessed" -ForegroundColor Yellow Write-Host "Workspace-based resources: $workspaceBasedCount" -ForegroundColor Yellow Write-Host "Legacy standalone resources: $legacyCount" -ForegroundColor Yellow Write-Host "Resources with complete tags (team, product, environment): $taggedResourcesCount" -ForegroundColor Yellow # Highlight areas needing attention if ($legacyCount -gt 0) { Write-Host "" Write-Host "RECOMMENDATIONS:" -ForegroundColor Cyan Write-Host "- $legacyCount legacy Application Insights resources should be migrated to workspace-based mode" -ForegroundColor Yellow } if ($taggedResourcesCount -lt $totalResourcesProcessed) { $untaggedCount = $totalResourcesProcessed - $taggedResourcesCount Write-Host "- $untaggedCount resources are missing required governance tags" -ForegroundColor Yellow } Write-Host "" Write-Host "Output file: $OutputPath" -ForegroundColor Yellow # Display results table Write-Host "" Write-Host "DETAILED RESULTS:" -ForegroundColor Cyan $Result | Format-Table -Property SubscriptionName, Name, ResourceGroupName, @{ Name = 'WorkspaceAssociated' Expression = { if ($_.WorkspaceResourceId) { 'Yes' } else { 'No' } } }, Tag_Team, Tag_Product, Tag_Environment -AutoSize Write-Host "========================================================================================================================================================================"