mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
added documetation
This commit is contained in:
@@ -1,67 +1,225 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Comprehensive Azure RBAC assignment analysis across entire Azure tenant.
|
||||
|
||||
.DESCRIPTION
|
||||
This script analyzes RBAC assignments across all Azure resources in an Azure tenant,
|
||||
providing a complete inventory of role assignments at every level of the Azure
|
||||
resource hierarchy. The script generates a detailed CSV report with comprehensive
|
||||
metadata including resource information, role assignments, and organizational tags.
|
||||
|
||||
Features:
|
||||
• Recursive analysis of Management Groups, Subscriptions, Resource Groups, and Resources
|
||||
• Complete RBAC assignment enumeration with role and principal details
|
||||
• Organizational metadata collection (tags, locations, resource types)
|
||||
• Hierarchical resource context (management group → subscription → resource group → resource)
|
||||
• Timestamped CSV output for historical tracking and compliance reporting
|
||||
• Comprehensive error handling to continue processing despite individual failures
|
||||
|
||||
.PARAMETER SubscriptionIds
|
||||
Optional array of specific subscription IDs to process. If not provided, all active
|
||||
subscriptions across all management groups will be processed. When specified, only
|
||||
the listed subscriptions will be analyzed for RBAC assignments.
|
||||
|
||||
.PARAMETER OutputPath
|
||||
Optional custom path for the output CSV file. If not provided, the file will be
|
||||
created in the current directory with a timestamped filename.
|
||||
|
||||
.EXAMPLE
|
||||
.\AzureRBAC.ps1
|
||||
Process all management groups and subscriptions to generate complete RBAC inventory.
|
||||
|
||||
.EXAMPLE
|
||||
.\AzureRBAC.ps1 -SubscriptionIds @("a134faf1-7a89-4f2c-8389-06d00bd5e2a7", "30ce4e64-4299-4b93-91b8-4c953f63678e")
|
||||
Process only the specified subscriptions for RBAC analysis.
|
||||
|
||||
.EXAMPLE
|
||||
.\AzureRBAC.ps1 -SubscriptionIds @("12345678-1234-1234-1234-123456789012") -OutputPath "C:\Reports\rbac-analysis.csv"
|
||||
Process a specific subscription and save results to a custom location.
|
||||
|
||||
.OUTPUTS
|
||||
CSV file: [YYYY-MM-DD HHMM] azure_rbac_assignments.csv
|
||||
|
||||
The output file contains the following columns:
|
||||
- ResourceId: Azure resource identifier
|
||||
- Id: Resource ID (for individual resources)
|
||||
- Kind: Resource type (ManagementGroup, Subscription, ResourceGroup, Resource)
|
||||
- Location: Azure region/location
|
||||
- ResourceName: Name of the resource
|
||||
- ResourceGroupName: Resource group containing the resource
|
||||
- ResourceType: Azure resource type (e.g., Microsoft.Storage/storageAccounts)
|
||||
- ManagementGroupId: Parent management group identifier
|
||||
- ManagementGroupName: Parent management group display name
|
||||
- SubscriptionId: Subscription identifier
|
||||
- SubscriptionName: Subscription display name
|
||||
- Tag_Team: Team tag value for organizational tracking
|
||||
- Tag_Product: Product tag value for product alignment
|
||||
- Tag_Environment: Environment tag value (Dev, Test, Prod, etc.)
|
||||
- Tag_Data: Data classification tag value
|
||||
- Tag_Delete: Deletion schedule tag value
|
||||
- Tag_Split: Cost allocation split tag value
|
||||
- RBAC_RoleAssignmentId: Unique role assignment identifier
|
||||
- RBAC_Scope: Scope where the role assignment is effective
|
||||
- RBAC_DisplayName: Display name of the assigned principal
|
||||
- RBAC_SignInName: Sign-in name/UPN of the assigned principal
|
||||
- RBAC_RoleDefinitionName: Name of the assigned Azure role
|
||||
|
||||
.NOTES
|
||||
Requires PowerShell modules: Az.Accounts, Az.Resources
|
||||
|
||||
Requires appropriate Azure RBAC permissions:
|
||||
• Reader access or higher on Management Groups
|
||||
• Reader access or higher on Subscriptions
|
||||
• Reader access or higher on Resource Groups and Resources
|
||||
• Microsoft.Authorization/roleAssignments/read permission at appropriate scopes
|
||||
|
||||
Authentication:
|
||||
• Must be authenticated to Azure (Connect-AzAccount) before running
|
||||
• Service Principal or Managed Identity authentication supported
|
||||
• Requires appropriate tenant-level permissions for comprehensive analysis
|
||||
|
||||
Performance Considerations:
|
||||
• Processing time scales with number of resources and role assignments
|
||||
• Large tenants may require several minutes to hours for complete analysis
|
||||
• Network connectivity and API throttling may affect processing speed
|
||||
• Memory usage scales with number of resources processed
|
||||
|
||||
Compatibility:
|
||||
• PowerShell 5.1 and PowerShell 7.x
|
||||
• Azure PowerShell module version 8.0 or later
|
||||
• Windows, macOS, and Linux support
|
||||
|
||||
Output Management:
|
||||
• CSV files are appended to support incremental data collection
|
||||
• Timestamped filenames prevent overwrites
|
||||
• Large result sets may generate substantial file sizes
|
||||
• Consider data retention and storage management policies
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/azure/role-based-access-control/
|
||||
https://docs.microsoft.com/en-us/powershell/azure/
|
||||
|
||||
AUTHOR: Cloud Engineering Team
|
||||
CREATED: Azure governance and compliance toolkit
|
||||
VERSION: 2.0 - Simplified RBAC analysis without PIM detection
|
||||
UPDATED: Focused on core RBAC assignment enumeration and organizational metadata
|
||||
#>
|
||||
|
||||
# Script parameters
|
||||
param(
|
||||
[Parameter(Mandatory = $false, HelpMessage = "Array of subscription IDs to process. If not specified, all subscriptions will be processed.")]
|
||||
[string[]]$SubscriptionIds = @(),
|
||||
|
||||
[Parameter(Mandatory = $false, HelpMessage = "Custom output path for the CSV file. If not specified, uses timestamped filename in current directory.")]
|
||||
[string]$OutputPath = ""
|
||||
)
|
||||
|
||||
#Connect-AzAccount
|
||||
Import-Module Az.Accounts
|
||||
Import-Module Az.Resources
|
||||
|
||||
# PowerShell class to represent Azure resource and RBAC assignment data
|
||||
class ResourceCheck {
|
||||
[string] $ResourceId = ""
|
||||
[string] $Id = ""
|
||||
[string] $Kind = ""
|
||||
[string] $Location = ""
|
||||
[string] $ResourceName = ""
|
||||
[string] $ResourceGroupName = ""
|
||||
[string] $ResourceType = ""
|
||||
[string] $ManagementGroupId = ""
|
||||
[string] $ManagementGroupName = ""
|
||||
[string] $SubscriptionId = ""
|
||||
[string] $SubscriptionName = ""
|
||||
[string] $Tag_Team = ""
|
||||
[string] $Tag_Product = ""
|
||||
[string] $Tag_Environment = ""
|
||||
[string] $Tag_Data = ""
|
||||
[string] $Tag_Delete = ""
|
||||
[string] $Tag_Split = ""
|
||||
[string] $RBAC_RoleAssignmentId = ""
|
||||
[string] $RBAC_Scope = ""
|
||||
[string] $RBAC_DisplayName = ""
|
||||
[string] $RBAC_SignInName = ""
|
||||
[string] $RBAC_RoleDefinitionName = ""
|
||||
# Resource identification and metadata
|
||||
[string] $ResourceId = "" # Azure resource identifier (full ARM path)
|
||||
[string] $Id = "" # Resource ID (used for individual resources)
|
||||
[string] $Kind = "" # Resource level (ManagementGroup, Subscription, ResourceGroup, Resource)
|
||||
[string] $Location = "" # Azure region/location where resource is deployed
|
||||
[string] $ResourceName = "" # Name of the resource
|
||||
[string] $ResourceGroupName = "" # Resource group containing the resource
|
||||
[string] $ResourceType = "" # Azure resource type (e.g., Microsoft.Storage/storageAccounts)
|
||||
|
||||
# Organizational hierarchy context
|
||||
[string] $ManagementGroupId = "" # Parent management group identifier
|
||||
[string] $ManagementGroupName = "" # Parent management group display name
|
||||
[string] $SubscriptionId = "" # Subscription identifier
|
||||
[string] $SubscriptionName = "" # Subscription display name
|
||||
|
||||
# Organizational metadata tags (customize based on organizational tagging strategy)
|
||||
[string] $Tag_Team = "" # Team responsible for the resource
|
||||
[string] $Tag_Product = "" # Product/application alignment
|
||||
[string] $Tag_Environment = "" # Environment classification (Dev, Test, Prod, etc.)
|
||||
[string] $Tag_Data = "" # Data classification level
|
||||
[string] $Tag_Delete = "" # Scheduled deletion information
|
||||
[string] $Tag_Split = "" # Cost allocation split information
|
||||
|
||||
# RBAC assignment details
|
||||
[string] $RBAC_RoleAssignmentId = "" # Unique identifier for the role assignment
|
||||
[string] $RBAC_Scope = "" # Scope where the role assignment is effective
|
||||
[string] $RBAC_DisplayName = "" # Display name of the assigned principal
|
||||
[string] $RBAC_SignInName = "" # Sign-in name/UPN of the assigned principal
|
||||
[string] $RBAC_RoleDefinitionName = "" # Name of the assigned Azure role
|
||||
}
|
||||
|
||||
# Display script execution banner
|
||||
Write-Host "========================================================================================================================================================================"
|
||||
Write-Host "Creating resource RBAC assignment overview."
|
||||
Write-Host "========================================================================================================================================================================"
|
||||
Write-Host "Azure RBAC Assignment Analysis"
|
||||
Write-Host "========================================================================================================================================================================"
|
||||
|
||||
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
|
||||
$fileName = ".\$date azure_rbac_assignments.csv"
|
||||
# Display processing scope information
|
||||
if ($SubscriptionIds.Count -gt 0) {
|
||||
Write-Host "SCOPE: Processing specific subscriptions only"
|
||||
Write-Host "Subscription IDs to process:"
|
||||
foreach ($subId in $SubscriptionIds) {
|
||||
Write-Host " - $subId"
|
||||
}
|
||||
} else {
|
||||
Write-Host "SCOPE: Processing ALL active subscriptions across all management groups"
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# Generate filename for output CSV (use custom path or default timestamped filename)
|
||||
if ($OutputPath -ne "") {
|
||||
$fileName = $OutputPath
|
||||
Write-Host "Using custom output file: $fileName"
|
||||
} else {
|
||||
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
|
||||
$fileName = ".\$date azure_rbac_assignments.csv"
|
||||
Write-Host "Using default timestamped filename: $fileName"
|
||||
}
|
||||
|
||||
# Discover all management groups in the tenant
|
||||
# This provides the top-level organizational structure for Azure resources
|
||||
$managementGroups = Get-AzManagementGroup
|
||||
|
||||
# Process each management group in the tenant
|
||||
foreach ($managementGroup in $managementGroups)
|
||||
{
|
||||
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
|
||||
Write-Host "Management group [$($managementGroup.Name)]"
|
||||
|
||||
# Initialize collection for management group level role assignments
|
||||
[ResourceCheck[]]$Result = @()
|
||||
|
||||
try {
|
||||
# Get role assignments directly assigned to this management group (not inherited)
|
||||
$roleAssignments = Get-AzRoleAssignment -Scope $managementGroup.Id | Where-Object Scope -eq $managementGroup.Id
|
||||
|
||||
# Process each role assignment at the management group level
|
||||
foreach($roleAssignment in $roleAssignments) {
|
||||
[ResourceCheck] $resourceCheck = [ResourceCheck]::new()
|
||||
$resourceCheck.ResourceId = ""
|
||||
$resourceCheck.Kind = "ManagementGroup"
|
||||
$resourceCheck.Location = ""
|
||||
$resourceCheck.ResourceGroupName = ""
|
||||
|
||||
# Set management group context (no individual resource context at this level)
|
||||
$resourceCheck.ResourceId = "" # No specific resource for MG assignments
|
||||
$resourceCheck.Kind = "ManagementGroup" # Indicates this is a management group level assignment
|
||||
$resourceCheck.Location = "" # Management groups don't have locations
|
||||
$resourceCheck.ResourceGroupName = "" # No resource group context
|
||||
$resourceCheck.ManagementGroupId = $managementGroup.Id
|
||||
$resourceCheck.ManagementGroupName = $managementGroup.DisplayName
|
||||
$resourceCheck.SubscriptionId = ""
|
||||
$resourceCheck.SubscriptionId = "" # No subscription context at MG level
|
||||
$resourceCheck.SubscriptionName = ""
|
||||
|
||||
# Management groups don't have tags in the same way resources do
|
||||
$resourceCheck.Tag_Team = ""
|
||||
$resourceCheck.Tag_Product = ""
|
||||
$resourceCheck.Tag_Environment = ""
|
||||
$resourceCheck.Tag_Data = ""
|
||||
$resourceCheck.Tag_Delete = ""
|
||||
$resourceCheck.Tag_Split = ""
|
||||
|
||||
# Populate RBAC assignment details
|
||||
$resourceCheck.RBAC_RoleAssignmentId = $roleAssignment.RoleAssignmentId
|
||||
$resourceCheck.RBAC_Scope = $roleAssignment.Scope
|
||||
$resourceCheck.RBAC_DisplayName = $roleAssignment.DisplayName
|
||||
@@ -75,39 +233,68 @@ foreach ($managementGroup in $managementGroups)
|
||||
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
|
||||
|
||||
|
||||
$subscriptions = Get-AzManagementGroupSubscription -Group $managementGroup.Name | Where-Object State -eq "Active"
|
||||
# Get all active subscriptions under this management group
|
||||
$allSubscriptions = Get-AzManagementGroupSubscription -Group $managementGroup.Name | Where-Object State -eq "Active"
|
||||
|
||||
# Filter subscriptions if specific subscription IDs were provided
|
||||
if ($SubscriptionIds.Count -gt 0) {
|
||||
$subscriptions = $allSubscriptions | Where-Object {
|
||||
$subscriptionId = $_.Id.Split('/')[-1] # Extract subscription ID from resource path
|
||||
$subscriptionId -in $SubscriptionIds
|
||||
}
|
||||
if ($subscriptions.Count -eq 0) {
|
||||
Write-Host "No matching subscriptions found in management group '$($managementGroup.DisplayName)' for the specified subscription IDs."
|
||||
continue
|
||||
}
|
||||
Write-Host "Processing $($subscriptions.Count) filtered subscription(s) in management group '$($managementGroup.DisplayName)'"
|
||||
} else {
|
||||
$subscriptions = $allSubscriptions
|
||||
Write-Host "Processing all $($subscriptions.Count) active subscription(s) in management group '$($managementGroup.DisplayName)'"
|
||||
}
|
||||
|
||||
# Process each subscription under the current management group
|
||||
foreach ($subscription in $subscriptions)
|
||||
{
|
||||
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
|
||||
|
||||
# Extract subscription ID from the full resource path
|
||||
$scope = $subscription.Id.Substring($subscription.Parent.Length, $subscription.Id.Length - $subscription.Parent.Length)
|
||||
$subscriptionId = $scope.Replace("/subscriptions/", "")
|
||||
Write-Host "Subscription [$($subscription.DisplayName) - $subscriptionId]"
|
||||
|
||||
# Set Azure PowerShell context to the current subscription
|
||||
Set-AzContext -SubscriptionId $subscriptionId | Out-Null
|
||||
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
|
||||
|
||||
# Initialize result array for this subscription's role assignments
|
||||
[ResourceCheck[]]$Result = @()
|
||||
|
||||
# Get role assignments directly assigned to this subscription scope
|
||||
try {
|
||||
$roleAssignments = Get-AzRoleAssignment -Scope $scope | Where-Object Scope -eq $scope
|
||||
|
||||
# Process each subscription-level role assignment
|
||||
foreach($roleAssignment in $roleAssignments) {
|
||||
[ResourceCheck] $resourceCheck = [ResourceCheck]::new()
|
||||
$resourceCheck.ResourceId = ""
|
||||
$resourceCheck.Kind = "Subscription"
|
||||
$resourceCheck.Location = ""
|
||||
$resourceCheck.ResourceGroupName = ""
|
||||
|
||||
# Set subscription context (no individual resource context at this level)
|
||||
$resourceCheck.ResourceId = "" # No specific resource for subscription assignments
|
||||
$resourceCheck.Kind = "Subscription" # Indicates this is a subscription level assignment
|
||||
$resourceCheck.Location = "" # Subscriptions don't have specific locations
|
||||
$resourceCheck.ResourceGroupName = "" # No resource group context at subscription level
|
||||
$resourceCheck.ManagementGroupId = $managementGroup.Id
|
||||
$resourceCheck.ManagementGroupName = $managementGroup.DisplayName
|
||||
$resourceCheck.SubscriptionId = $subscription.Id
|
||||
$resourceCheck.SubscriptionName = $subscription.DisplayName
|
||||
# Extract subscription-level tags if available
|
||||
$resourceCheck.Tag_Team = $subscription.Tags.team
|
||||
$resourceCheck.Tag_Product = $subscription.Tags.product
|
||||
$resourceCheck.Tag_Environment = $subscription.Tags.environment
|
||||
$resourceCheck.Tag_Data = $subscription.Tags.data
|
||||
$resourceCheck.Tag_Delete = $subscription.Tags.delete
|
||||
$resourceCheck.Tag_Split = $subscription.Tags.split
|
||||
|
||||
# Populate RBAC assignment details
|
||||
$resourceCheck.RBAC_RoleAssignmentId = $roleAssignment.RoleAssignmentId
|
||||
$resourceCheck.RBAC_Scope = $roleAssignment.Scope
|
||||
$resourceCheck.RBAC_DisplayName = $roleAssignment.DisplayName
|
||||
@@ -117,34 +304,46 @@ foreach ($managementGroup in $managementGroups)
|
||||
$Result += $resourceCheck
|
||||
}
|
||||
} catch {
|
||||
# Silently handle any errors during subscription-level role assignment processing
|
||||
}
|
||||
# Export subscription-level role assignments to CSV
|
||||
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
|
||||
|
||||
# Get all resource groups within the current subscription
|
||||
$resourceGroups = Get-AzResourceGroup
|
||||
|
||||
# Process each resource group for RBAC assignments
|
||||
foreach ($resourceGroup in $resourceGroups) {
|
||||
|
||||
# Initialize result array for this resource group's role assignments
|
||||
[ResourceCheck[]]$Result = @()
|
||||
|
||||
# Get role assignments at resource group level and below
|
||||
try {
|
||||
$roleAssignments = Get-AzRoleAssignment -Scope $resourceGroup.ResourceId | Where-Object Scope -Like "$($resourceGroup.ResourceId)*"
|
||||
|
||||
# Process each resource group-level role assignment
|
||||
foreach($roleAssignment in $roleAssignments) {
|
||||
[ResourceCheck] $resourceCheck = [ResourceCheck]::new()
|
||||
# Set resource group context
|
||||
$resourceCheck.ResourceId = $resourceGroup.ResourceId
|
||||
$resourceCheck.Kind = "ResourceGroup"
|
||||
$resourceCheck.Kind = "ResourceGroup" # Indicates this is a resource group level assignment
|
||||
$resourceCheck.Location = $resourceGroup.Location
|
||||
$resourceCheck.ResourceGroupName = $resourceGroup.ResourceGroupName
|
||||
$resourceCheck.ManagementGroupId = $managementGroup.Id
|
||||
$resourceCheck.ManagementGroupName = $managementGroup.DisplayName
|
||||
$resourceCheck.SubscriptionId = $subscription.Id
|
||||
$resourceCheck.SubscriptionName = $subscription.DisplayName
|
||||
|
||||
# Extract resource group-level tags if available
|
||||
$resourceCheck.Tag_Team = $resourceGroup.Tags.team
|
||||
$resourceCheck.Tag_Product = $resourceGroup.Tags.product
|
||||
$resourceCheck.Tag_Environment = $resourceGroup.Tags.environment
|
||||
$resourceCheck.Tag_Data = $resourceGroup.Tags.data
|
||||
$resourceCheck.Tag_Delete = $resourceGroup.Tags.delete
|
||||
$resourceCheck.Tag_Split = $resourceGroup.Tags.split
|
||||
|
||||
# Populate RBAC assignment details
|
||||
$resourceCheck.RBAC_RoleAssignmentId = $roleAssignment.RoleAssignmentId
|
||||
$resourceCheck.RBAC_Scope = $roleAssignment.Scope
|
||||
$resourceCheck.RBAC_DisplayName = $roleAssignment.DisplayName
|
||||
@@ -154,38 +353,51 @@ foreach ($managementGroup in $managementGroups)
|
||||
$Result += $resourceCheck
|
||||
}
|
||||
} catch {
|
||||
# Silently handle any errors during resource group-level role assignment processing
|
||||
}
|
||||
# Export resource group-level role assignments to CSV
|
||||
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
|
||||
}
|
||||
|
||||
# Get all individual resources within the current subscription
|
||||
$allResources = Get-AzResource
|
||||
|
||||
# Process each individual resource for RBAC assignments
|
||||
foreach ($resource in $allResources) {
|
||||
|
||||
# Initialize result array for this resource's role assignments
|
||||
[ResourceCheck[]]$Result = @()
|
||||
|
||||
# Get role assignments directly assigned to this specific resource
|
||||
try {
|
||||
$roleAssignments = Get-AzRoleAssignment -Scope $resource.ResourceId | Where-Object Scope -eq $resource.ResourceId
|
||||
|
||||
# Process each resource-level role assignment
|
||||
foreach($roleAssignment in $roleAssignments) {
|
||||
[ResourceCheck] $resourceCheck = [ResourceCheck]::new()
|
||||
|
||||
# Set individual resource context with full metadata
|
||||
$resourceCheck.ResourceId = $resource.ResourceId
|
||||
$resourceCheck.Id = $resource.Id
|
||||
$resourceCheck.Kind = "Resource"
|
||||
$resourceCheck.Id = $resource.Id # Additional resource identifier
|
||||
$resourceCheck.Kind = "Resource" # Indicates this is an individual resource assignment
|
||||
$resourceCheck.Location = $resource.Location
|
||||
$resourceCheck.ResourceName = $resource.ResourceName
|
||||
$resourceCheck.ResourceGroupName = $resource.ResourceGroupName
|
||||
$resourceCheck.ResourceType = $resource.ResourceType
|
||||
$resourceCheck.ResourceType = $resource.ResourceType # e.g., Microsoft.Storage/storageAccounts
|
||||
$resourceCheck.ManagementGroupId = $managementGroup.Id
|
||||
$resourceCheck.ManagementGroupName = $managementGroup.DisplayName
|
||||
$resourceCheck.SubscriptionId = $subscription.Id
|
||||
$resourceCheck.SubscriptionName = $subscription.DisplayName
|
||||
|
||||
# Extract resource-level tags if available
|
||||
$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
|
||||
|
||||
# Populate RBAC assignment details
|
||||
$resourceCheck.RBAC_RoleAssignmentId = $roleAssignment.RoleAssignmentId
|
||||
$resourceCheck.RBAC_Scope = $roleAssignment.Scope
|
||||
$resourceCheck.RBAC_DisplayName = $roleAssignment.DisplayName
|
||||
@@ -195,11 +407,20 @@ foreach ($managementGroup in $managementGroups)
|
||||
$Result += $resourceCheck
|
||||
}
|
||||
} catch {
|
||||
# Silently handle any errors during individual resource-level role assignment processing
|
||||
}
|
||||
# Export individual resource-level role assignments to CSV
|
||||
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Final completion message
|
||||
Write-Host "========================================================================================================================================================================"
|
||||
if ($SubscriptionIds.Count -gt 0) {
|
||||
Write-Host "RBAC analysis complete for $($SubscriptionIds.Count) specified subscription(s)."
|
||||
} else {
|
||||
Write-Host "RBAC analysis complete for all active subscriptions across all management groups."
|
||||
}
|
||||
Write-Host "Results exported to: $fileName"
|
||||
Write-Host "Done."
|
||||
|
||||
Reference in New Issue
Block a user