While trying to find a proper script which can list all the resources across all the subscriptions in an Azure tenancy, I had tried few variations of PowerShell scripts, which gave some details but not what I had visualised and not in the same format or speed.
I had asked Cline AI bot to help with a python script instead which will produce the same level of details and it sure did come up with the proper script along with the documentation of the script (readme file). We tried on an Azure tenancy with 31 subscription an dit had listed around 7800 resources. The script also has a feature to display the progress update on what is happening with the subscription resource, e.g. number of resources discovered out of the total, looks impressive.
Read Me file which explains what is being done.
# Azure Comprehensive Inventory Tool
A Python script that extracts a full inventory of Azure resources within an Azure Tenant (across all subscriptions) and exports them to a detailed Excel workbook.
## Features
ā **Comprehensive Resource Discovery**
– Scans all enabled subscriptions in your Azure tenant
– Lists ALL resource types with base information
– Extracts detailed configuration for common resource types
ā **Detailed Resource Information**
– **Virtual Machines**: Size, OS type/version, power state, disk info, networking
– **Storage Accounts**: SKU, encryption, network access, TLS settings
– **Key Vaults**: Security settings, soft delete, purge protection, RBAC
– **SQL Servers**: Version, authentication, database count, firewall rules
– **Network Interfaces**: Private/Public IPs, accelerated networking
– **Disks**: Size, state, SKU, encryption, managed by info
– **All Resources**: Name, type, location, resource group, tags, resource ID
ā **Excel Output**
– Single worksheet with one resource per row
– Formatted headers with filters
– Auto-adjusted column widths
– Frozen header row for easy scrolling
– Sorted by subscription, resource type, and name
## Prerequisites
1. **Python 3.8 or higher**
2. **Azure CLI** (for authentication)
3. **Azure Subscription Access** (Reader role minimum)
## Installation
### Step 1: Install Azure CLI
**macOS:**
“`bash
brew update && brew install azure-cli
“`
**Windows:**
Download and install from: https://aka.ms/installazurecliwindows
**Linux:**
“`bash
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
“`
### Step 2: Clone or Download the Script
“`bash
cd ~/Downloads/PS-Scripts/Inventory
“`
### Step 3: Install Python Dependencies
“`bash
pip install -r requirements.txt
“`
Or install manually:
“`bash
pip install azure-identity azure-mgmt-resource azure-mgmt-compute azure-mgmt-storage \
azure-mgmt-network azure-mgmt-sql azure-mgmt-keyvault azure-mgmt-monitor \
azure-mgmt-recoveryservices azure-mgmt-recoveryservicesbackup azure-mgmt-security \
pandas openpyxl
“`
## Usage
### Step 1: Login to Azure
“`bash
az login
“`
If you have multiple tenants, specify the tenant:
“`bash
az login –tenant “your-tenant-id”
“`
### Step 2: Run the Script
**Basic usage (default output file):**
“`bash
python azure_inventory.py
“`
**Specify output file:**
“`bash
python azure_inventory.py -o my_azure_inventory.xlsx
“`
**Specify tenant ID:**
“`bash
python azure_inventory.py –tenant-id “12345678-1234-1234-1234-123456789012”
“`
**Full example:**
“`bash
python azure_inventory.py -o /Users/karthiksankaran/Desktop/Azure_Inventory.xlsx
“`
## Output Format
The Excel file contains a single worksheet named `Azure_Inventory` with columns including:
### Common Columns (All Resources)
– Subscription_Name
– Subscription_ID
– Resource_Name
– Resource_Type
– Resource_Group
– Location
– Tags
– Resource_ID
– Provisioning_State
### Resource-Specific Columns
**Virtual Machines:**
– VM_Size, OS_Type, OS_Version, Power_State, Admin_Username, Computer_Name
– License_Type, Boot_Diagnostics, OS_Disk_Size_GB, Data_Disk_Count, NIC_Count
**Storage Accounts:**
– SKU, Kind, Access_Tier, Creation_Time, Public_Network_Access
– Allow_Blob_Public_Access, Min_TLS_Version, HTTPS_Only
– Blob_Encryption, File_Encryption
**Key Vaults:**
– SKU, Enabled_For_Deployment, Enabled_For_Disk_Encryption
– Soft_Delete_Enabled, Soft_Delete_Retention_Days, Purge_Protection
– RBAC_Authorization, Public_Network_Access, Vault_URI
**SQL Servers:**
– Version, State, FQDN, Admin_Login, Public_Network_Access
– Min_TLS_Version, AAD_Only_Auth, Database_Count
**Network Interfaces:**
– Private_IPs, Public_IPs, Primary, Enable_Accelerated_Networking
– Enable_IP_Forwarding
**Disks:**
– Disk_Size_GB, Disk_State, SKU, OS_Type, Encryption_Type
– Network_Access_Policy, Managed_By
## Command Line Options
“`
usage: azure_inventory.py [-h] [-t TENANT_ID] [-o OUTPUT]
Azure Comprehensive Resource Inventory Tool
optional arguments:
-h, –help Show this help message and exit
-t TENANT_ID, –tenant-id TENANT_ID
Azure Tenant ID (optional if already logged in)
-o OUTPUT, –output OUTPUT
Output Excel file path (default: Azure_Inventory_YYYYMMDD_HHMMSS.xlsx)
“`
## Troubleshooting
### Authentication Issues
**Problem:** “Failed to authenticate”
“`bash
# Solution: Login to Azure CLI
az login
az account show # Verify you’re logged in
“`
### Missing Packages
**Problem:** “Missing required package”
“`bash
# Solution: Install all requirements
pip install -r requirements.txt
“`
### Permission Issues
**Problem:** “Authorization failed” or “Access denied”
“`bash
# Solution: Ensure you have at least Reader role on subscriptions
# Check your access:
az role assignment list –assignee [email protected] –output table
“`
### No Resources Found
**Problem:** Script completes but shows 0 resources
– Verify subscriptions are enabled: `az account list –output table`
– Check if you have access to the subscription
– Ensure the subscription contains resources
## Performance Notes
– **Large Tenants**: For tenants with 1000+ resources, expect 5-15 minutes runtime
– **API Rate Limits**: The script handles Azure API throttling automatically
– **Progress Indicators**: Shows progress every 50 resources processed
## Security Considerations
– Uses Azure CLI authentication (no credentials stored in script)
– Requires only **Reader** role permission
– No data is sent outside your Azure tenant
– Excel file contains sensitive information – store securely
## Example Output
“`
======================================================================
Azure Comprehensive Resource Inventory
======================================================================
ā Using Azure CLI credentials
š Retrieving subscriptions…
ā Found 3 enabled subscription(s)
š Processing subscription: Production-Subscription
Found 245 resources
Processing resource 50/245…
Processing resource 100/245…
Processing resource 150/245…
Processing resource 200/245…
ā Completed processing Production-Subscription
š Processing subscription: Development-Subscription
Found 128 resources
Processing resource 50/128…
Processing resource 100/128…
ā Completed processing Development-Subscription
š Exporting to Excel: Azure_Inventory_20251016_162534.xlsx
ā Successfully exported 373 resources to Excel
ā File saved: Azure_Inventory_20251016_162534.xlsx
======================================================================
ā Inventory collection completed!
ā Total resources collected: 373
ā Output file: Azure_Inventory_20251016_162534.xlsx
======================================================================
“`
## Support
For issues or questions:
1. Check the troubleshooting section above
2. Verify Azure CLI is properly configured: `az account show`
3. Ensure all dependencies are installed: `pip list | grep azure`
## License
This script is provided as-is for Azure resource inventory purposes.
## Version
– **Version**: 1.0
– **Date**: 2025-10-16
– **Azure SDK**: Latest stable versions
– **Python**: 3.8+
The Requiremets.txt file is as below:
# Azure SDK packages
azure-identity>=1.15.0
azure-mgmt-resource>=23.0.0
azure-mgmt-compute>=30.0.0
azure-mgmt-storage>=21.0.0
azure-mgmt-network>=25.0.0
azure-mgmt-sql>=3.0.0
azure-mgmt-keyvault>=10.0.0
azure-mgmt-monitor>=6.0.0
azure-mgmt-recoveryservices>=2.0.0
azure-mgmt-recoveryservicesbackup>=9.0.0
azure-mgmt-security>=6.0.0
# Data processing and Excel export
pandas>=2.0.0
openpyxl>=3.1.0
The Main Script “azure_inventory.py: is below
#!/usr/bin/env python3
"""
Azure Comprehensive Inventory Script
Creates a detailed Excel inventory of all Azure resources across all subscriptions in a tenant.
Each resource is listed with comprehensive details in a single row.
"""
import os
import sys
from datetime import datetime
from typing import List, Dict, Any
import argparse
try:
from azure.identity import DefaultAzureCredential, AzureCliCredential
from azure.mgmt.resource import ResourceManagementClient, SubscriptionClient
from azure.mgmt.compute import ComputeManagementClient
from azure.mgmt.storage import StorageManagementClient
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.sql import SqlManagementClient
from azure.mgmt.keyvault import KeyVaultManagementClient
from azure.mgmt.monitor import MonitorManagementClient
from azure.mgmt.recoveryservices import RecoveryServicesClient
from azure.mgmt.recoveryservicesbackup import RecoveryServicesBackupClient
from azure.mgmt.security import SecurityCenter
import pandas as pd
from openpyxl import load_workbook
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.utils import get_column_letter
except ImportError as e:
print(f"Error: Missing required package - {e}")
print("\nPlease install required packages:")
print("pip install azure-identity azure-mgmt-resource azure-mgmt-compute azure-mgmt-storage")
print("pip install azure-mgmt-network azure-mgmt-sql azure-mgmt-keyvault azure-mgmt-monitor")
print("pip install azure-mgmt-recoveryservices azure-mgmt-recoveryservicesbackup azure-mgmt-security")
print("pip install pandas openpyxl")
sys.exit(1)
class AzureInventoryCollector:
"""Collects comprehensive Azure resource inventory."""
def __init__(self, tenant_id: str = None):
self.tenant_id = tenant_id
self.credential = None
self.inventory_data = []
self.subscription_data = {} # Store data per subscription
self.initialize_credential()
def initialize_credential(self):
"""Initialize Azure credentials."""
try:
# Try Azure CLI credential first
self.credential = AzureCliCredential()
print("ā Using Azure CLI credentials")
except Exception:
try:
# Fall back to default credential
self.credential = DefaultAzureCredential()
print("ā Using Default Azure credentials")
except Exception as e:
print(f"ā Failed to authenticate: {e}")
print("\nPlease run: az login")
sys.exit(1)
def get_subscriptions(self) -> List[Dict]:
"""Get all enabled subscriptions in the tenant."""
print("\nš Retrieving subscriptions...")
subscription_client = SubscriptionClient(self.credential)
subscriptions = []
try:
for sub in subscription_client.subscriptions.list():
if sub.state == "Enabled":
subscriptions.append({
'id': sub.subscription_id,
'name': sub.display_name,
'state': sub.state
})
print(f"ā Found {len(subscriptions)} enabled subscription(s)")
return subscriptions
except Exception as e:
print(f"ā Error retrieving subscriptions: {e}")
return []
def get_vm_details(self, resource: Any, subscription_id: str) -> Dict:
"""Get detailed VM information."""
try:
compute_client = ComputeManagementClient(self.credential, subscription_id)
vm = compute_client.virtual_machines.get(
resource.id.split('/')[4], # resource group
resource.name,
expand='instanceView'
)
# Get power state
power_state = "Unknown"
if vm.instance_view and vm.instance_view.statuses:
for status in vm.instance_view.statuses:
if status.code.startswith('PowerState/'):
power_state = status.code.replace('PowerState/', '')
# Get OS info
os_type = vm.storage_profile.os_disk.os_type if vm.storage_profile.os_disk else "Unknown"
os_version = "Unknown"
if vm.storage_profile.image_reference:
img_ref = vm.storage_profile.image_reference
os_version = f"{img_ref.offer or ''} {img_ref.sku or ''}".strip()
return {
'VM_Size': vm.hardware_profile.vm_size if vm.hardware_profile else 'Unknown',
'OS_Type': os_type,
'OS_Version': os_version,
'Power_State': power_state,
'Provisioning_State': vm.provisioning_state,
'Admin_Username': vm.os_profile.admin_username if vm.os_profile else 'Unknown',
'Computer_Name': vm.os_profile.computer_name if vm.os_profile else 'Unknown',
'License_Type': vm.license_type or 'None',
'Boot_Diagnostics': str(vm.diagnostics_profile.boot_diagnostics.enabled) if vm.diagnostics_profile and vm.diagnostics_profile.boot_diagnostics else 'False',
'OS_Disk_Size_GB': vm.storage_profile.os_disk.disk_size_gb if vm.storage_profile.os_disk else 'Unknown',
'Data_Disk_Count': len(vm.storage_profile.data_disks) if vm.storage_profile.data_disks else 0,
'NIC_Count': len(vm.network_profile.network_interfaces) if vm.network_profile and vm.network_profile.network_interfaces else 0,
}
except Exception as e:
return {'Error': str(e)}
def get_storage_details(self, resource: Any, subscription_id: str) -> Dict:
"""Get detailed Storage Account information."""
try:
storage_client = StorageManagementClient(self.credential, subscription_id)
storage = storage_client.storage_accounts.get_properties(
resource.id.split('/')[4],
resource.name
)
return {
'SKU': storage.sku.name if storage.sku else 'Unknown',
'Kind': storage.kind or 'Unknown',
'Access_Tier': storage.access_tier or 'N/A',
'Creation_Time': str(storage.creation_time) if storage.creation_time else 'Unknown',
'Primary_Location': storage.primary_location or 'Unknown',
'Status': storage.status_of_primary or 'Unknown',
'Public_Network_Access': storage.public_network_access or 'Enabled',
'Allow_Blob_Public_Access': str(storage.allow_blob_public_access) if storage.allow_blob_public_access is not None else 'Unknown',
'Min_TLS_Version': storage.minimum_tls_version or 'Unknown',
'HTTPS_Only': str(storage.enable_https_traffic_only) if storage.enable_https_traffic_only is not None else 'Unknown',
'Blob_Encryption': str(storage.encryption.services.blob.enabled) if storage.encryption and storage.encryption.services.blob else 'Unknown',
'File_Encryption': str(storage.encryption.services.file.enabled) if storage.encryption and storage.encryption.services.file else 'Unknown',
}
except Exception as e:
return {'Error': str(e)}
def get_keyvault_details(self, resource: Any, subscription_id: str) -> Dict:
"""Get detailed Key Vault information."""
try:
kv_client = KeyVaultManagementClient(self.credential, subscription_id)
vault = kv_client.vaults.get(
resource.id.split('/')[4],
resource.name
)
return {
'SKU': vault.properties.sku.name if vault.properties.sku else 'Unknown',
'Enabled_For_Deployment': str(vault.properties.enabled_for_deployment) if vault.properties.enabled_for_deployment is not None else 'Unknown',
'Enabled_For_Disk_Encryption': str(vault.properties.enabled_for_disk_encryption) if vault.properties.enabled_for_disk_encryption is not None else 'Unknown',
'Enabled_For_Template_Deployment': str(vault.properties.enabled_for_template_deployment) if vault.properties.enabled_for_template_deployment is not None else 'Unknown',
'Soft_Delete_Enabled': str(vault.properties.enable_soft_delete) if vault.properties.enable_soft_delete is not None else 'Unknown',
'Soft_Delete_Retention_Days': vault.properties.soft_delete_retention_in_days or 'Unknown',
'Purge_Protection': str(vault.properties.enable_purge_protection) if vault.properties.enable_purge_protection is not None else 'Unknown',
'RBAC_Authorization': str(vault.properties.enable_rbac_authorization) if vault.properties.enable_rbac_authorization is not None else 'Unknown',
'Public_Network_Access': vault.properties.public_network_access or 'Enabled',
'Vault_URI': vault.properties.vault_uri or 'Unknown',
}
except Exception as e:
return {'Error': str(e)}
def get_sql_server_details(self, resource: Any, subscription_id: str) -> Dict:
"""Get detailed SQL Server information."""
try:
sql_client = SqlManagementClient(self.credential, subscription_id)
server = sql_client.servers.get(
resource.id.split('/')[4],
resource.name
)
# Get database count
db_count = 0
try:
databases = list(sql_client.databases.list_by_server(
resource.id.split('/')[4],
resource.name
))
db_count = len([db for db in databases if db.name != 'master'])
except:
pass
return {
'Version': server.version or 'Unknown',
'State': server.state or 'Unknown',
'FQDN': server.fully_qualified_domain_name or 'Unknown',
'Admin_Login': server.administrator_login or 'Unknown',
'Public_Network_Access': server.public_network_access or 'Unknown',
'Min_TLS_Version': server.minimal_tls_version or 'Unknown',
'AAD_Only_Auth': str(server.administrators.azure_ad_only_authentication) if server.administrators and hasattr(server.administrators, 'azure_ad_only_authentication') else 'Unknown',
'Database_Count': db_count,
}
except Exception as e:
return {'Error': str(e)}
def get_network_interface_details(self, resource: Any, subscription_id: str) -> Dict:
"""Get detailed Network Interface information."""
try:
network_client = NetworkManagementClient(self.credential, subscription_id)
nic = network_client.network_interfaces.get(
resource.id.split('/')[4],
resource.name
)
private_ips = []
public_ips = []
if nic.ip_configurations:
for ip_config in nic.ip_configurations:
if ip_config.private_ip_address:
private_ips.append(ip_config.private_ip_address)
if ip_config.public_ip_address:
public_ips.append(ip_config.public_ip_address.id.split('/')[-1])
return {
'Private_IPs': ', '.join(private_ips) if private_ips else 'None',
'Public_IPs': ', '.join(public_ips) if public_ips else 'None',
'Primary': str(nic.primary) if nic.primary is not None else 'Unknown',
'Enable_Accelerated_Networking': str(nic.enable_accelerated_networking) if nic.enable_accelerated_networking is not None else 'Unknown',
'Enable_IP_Forwarding': str(nic.enable_ip_forwarding) if nic.enable_ip_forwarding is not None else 'Unknown',
}
except Exception as e:
return {'Error': str(e)}
def get_disk_details(self, resource: Any, subscription_id: str) -> Dict:
"""Get detailed Disk information."""
try:
compute_client = ComputeManagementClient(self.credential, subscription_id)
disk = compute_client.disks.get(
resource.id.split('/')[4],
resource.name
)
return {
'Disk_Size_GB': disk.disk_size_gb or 'Unknown',
'Disk_State': disk.disk_state or 'Unknown',
'SKU': disk.sku.name if disk.sku else 'Unknown',
'OS_Type': disk.os_type or 'None',
'Encryption_Type': disk.encryption.type if disk.encryption else 'Unknown',
'Network_Access_Policy': disk.network_access_policy or 'Unknown',
'Managed_By': disk.managed_by.split('/')[-1] if disk.managed_by else 'None',
}
except Exception as e:
return {'Error': str(e)}
def format_tags(self, tags: Dict) -> str:
"""Format tags dictionary as string."""
if not tags:
return 'None'
return '; '.join([f"{k}={v}" for k, v in tags.items()])
def collect_subscription_resources(self, subscription: Dict):
"""Collect all resources from a subscription."""
subscription_id = subscription['id']
subscription_name = subscription['name']
print(f"\nš Processing subscription: {subscription_name}")
# Initialize list for this subscription
if subscription_name not in self.subscription_data:
self.subscription_data[subscription_name] = []
try:
resource_client = ResourceManagementClient(self.credential, subscription_id)
resources = list(resource_client.resources.list())
print(f" Found {len(resources)} resources")
for idx, resource in enumerate(resources, 1):
if idx % 50 == 0:
print(f" Processing resource {idx}/{len(resources)}...")
# Base resource information
resource_data = {
'Subscription_Name': subscription_name,
'Subscription_ID': subscription_id,
'Resource_Name': resource.name,
'Resource_Type': resource.type,
'Resource_Group': resource.id.split('/')[4] if len(resource.id.split('/')) > 4 else 'Unknown',
'Location': resource.location or 'Unknown',
'Tags': self.format_tags(resource.tags),
'Resource_ID': resource.id,
'Provisioning_State': getattr(resource, 'provisioning_state', 'Unknown'),
}
# Get resource-specific details based on type
resource_type = resource.type.lower()
if 'microsoft.compute/virtualmachines' in resource_type and '/extensions' not in resource_type:
details = self.get_vm_details(resource, subscription_id)
resource_data.update(details)
elif 'microsoft.storage/storageaccounts' in resource_type:
details = self.get_storage_details(resource, subscription_id)
resource_data.update(details)
elif 'microsoft.keyvault/vaults' in resource_type:
details = self.get_keyvault_details(resource, subscription_id)
resource_data.update(details)
elif 'microsoft.sql/servers' in resource_type and '/databases' not in resource_type:
details = self.get_sql_server_details(resource, subscription_id)
resource_data.update(details)
elif 'microsoft.network/networkinterfaces' in resource_type:
details = self.get_network_interface_details(resource, subscription_id)
resource_data.update(details)
elif 'microsoft.compute/disks' in resource_type:
details = self.get_disk_details(resource, subscription_id)
resource_data.update(details)
# Add to both global and subscription-specific lists
self.inventory_data.append(resource_data)
self.subscription_data[subscription_name].append(resource_data)
print(f"ā Completed processing {subscription_name}")
except Exception as e:
print(f"ā Error processing subscription {subscription_name}: {e}")
def export_to_excel(self, output_path: str):
"""Export inventory data to Excel with formatting - one worksheet per subscription."""
print(f"\nš Exporting to Excel: {output_path}")
if not self.inventory_data:
print("ā No data to export!")
return
def format_worksheet(worksheet, worksheet_name):
"""Apply formatting to a worksheet."""
# Header formatting
header_fill = PatternFill(start_color='366092', end_color='366092', fill_type='solid')
header_font = Font(bold=True, color='FFFFFF')
for cell in worksheet[1]:
cell.fill = header_fill
cell.font = header_font
cell.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
# Auto-adjust column widths
for column in worksheet.columns:
max_length = 0
column_letter = get_column_letter(column[0].column)
for cell in column:
try:
if cell.value:
max_length = max(max_length, len(str(cell.value)))
except:
pass
adjusted_width = min(max_length + 2, 50)
worksheet.column_dimensions[column_letter].width = adjusted_width
# Freeze the header row
worksheet.freeze_panes = 'A2'
# Add autofilter
worksheet.auto_filter.ref = worksheet.dimensions
# Export to Excel with separate worksheets per subscription
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
# Create a worksheet for each subscription
for sub_name, sub_resources in self.subscription_data.items():
if sub_resources: # Only create worksheet if there are resources
df = pd.DataFrame(sub_resources)
df = df.sort_values(['Resource_Type', 'Resource_Name'])
# Clean subscription name for worksheet (Excel has 31 char limit)
sheet_name = sub_name[:31].replace(':', '-').replace('/', '-').replace('\\', '-').replace('?', '-').replace('*', '-').replace('[', '-').replace(']', '-')
df.to_excel(writer, sheet_name=sheet_name, index=False)
# Format the worksheet
worksheet = writer.sheets[sheet_name]
format_worksheet(worksheet, sheet_name)
print(f" ā Created worksheet: {sheet_name} ({len(sub_resources)} resources)")
# Also create a summary worksheet with all resources
df_all = pd.DataFrame(self.inventory_data)
df_all = df_all.sort_values(['Subscription_Name', 'Resource_Type', 'Resource_Name'])
df_all.to_excel(writer, sheet_name='All_Subscriptions', index=False)
# Format the summary worksheet
worksheet = writer.sheets['All_Subscriptions']
format_worksheet(worksheet, 'All_Subscriptions')
print(f" ā Created summary worksheet: All_Subscriptions ({len(self.inventory_data)} resources)")
print(f"\nā Successfully exported {len(self.inventory_data)} resources to Excel")
print(f"ā Created {len(self.subscription_data)} subscription worksheets + 1 summary worksheet")
print(f"ā File saved: {output_path}")
def main():
"""Main execution function."""
parser = argparse.ArgumentParser(
description='Azure Comprehensive Resource Inventory Tool',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
Examples:
python azure_inventory.py
python azure_inventory.py -o /path/to/output/inventory.xlsx
python azure_inventory.py --tenant-id "your-tenant-id"
'''
)
parser.add_argument(
'-t', '--tenant-id',
help='Azure Tenant ID (optional if already logged in)',
default=None
)
parser.add_argument(
'-o', '--output',
help='Output Excel file path',
default=f'Azure_Inventory_{datetime.now().strftime("%Y%m%d_%H%M%S")}.xlsx'
)
args = parser.parse_args()
print("=" * 70)
print("Azure Comprehensive Resource Inventory")
print("=" * 70)
# Initialize collector
collector = AzureInventoryCollector(tenant_id=args.tenant_id)
# Get subscriptions
subscriptions = collector.get_subscriptions()
if not subscriptions:
print("\nā No subscriptions found or accessible")
sys.exit(1)
# Collect resources from all subscriptions
for subscription in subscriptions:
collector.collect_subscription_resources(subscription)
# Export to Excel
if collector.inventory_data:
collector.export_to_excel(args.output)
print("\n" + "=" * 70)
print(f"ā Inventory collection completed!")
print(f"ā Total resources collected: {len(collector.inventory_data)}")
print(f"ā Output file: {args.output}")
print("=" * 70)
else:
print("\nā No resources collected")
sys.exit(1)
if __name__ == '__main__':
main()
Hope you find it useful.