diff --git a/e2e_samples/parking_sensors/utilities/README_pause_resume_synapse.md b/e2e_samples/parking_sensors/utilities/README_pause_resume_synapse.md new file mode 100644 index 000000000..be46d36c8 --- /dev/null +++ b/e2e_samples/parking_sensors/utilities/README_pause_resume_synapse.md @@ -0,0 +1,304 @@ +# Pause/Resume Azure Synapse SQL Pools and Azure SQL Data Warehouse Script + +## Overview + +This PowerShell script is designed to automate the pausing or resuming of Azure Synapse SQL Pools and Azure SQL Data Warehouse (Dedicated SQL Pools). This functionality helps organizations optimize costs by pausing unused resources and resuming them when needed. + +It supports both manual execution and deployment as an Azure Automation Runbook with a Managed Identity, making it ideal for scheduled automation tasks. + +--- + +## Features + +- **Automated Pause/Resume**: + - Dynamically pause or resume SQL Pools across specific or all resource groups. +- **Flexible Execution**: + - Run locally with PowerShell or automate through Azure Automation. +- **Custom Parameters**: + - Specify environments (e.g., dev, stg, prod) and projects for targeted execution. +- **Error and Warning Tracking**: + - Logs all errors and warnings, providing a detailed summary at the end. +- **Dry Run Mode**: + - Simulate actions without making changes to validate configurations. + +--- + +## Parameters + +| Parameter | Description | Default | Example | +|------------------|---------------------------------------------------------------------------------------------------------|-----------|----------------------------------------------| +| `SubscriptionId` | Azure Subscription ID. Required for local execution. | | `12345678-1234-1234-1234-123456789abc` | +| `DeploymentIds` | Comma-separated deployment IDs. Required if `ResourceGroups` is not provided. Specific to Databricks E2E use case. | | `tst01, tst02` | +| `Project` | Project name. Required if `ResourceGroups` is not provided. Specific to Databricks E2E use case. | | `mdwdops` | +| `Environments` | Environments (e.g., dev, stg, prod). | `dev,stg` | `dev,stg,prod` | +| `ResourceGroups` | Comma-separated list of resource groups. Use `*` to target all resource groups in the subscription. | | `mdwdops-tst01-dev-rg,mdwdops-tst01-stg-rg` | +| `Action` | Specify `Pause` or `Resume`. | `Pause` | `Pause` | +| `DryRun` | Simulate actions without making changes. | `false` | `false` | +| `InstallModules` | Install missing modules if not present. | `false` | `true` | + +--- + +## Example Scenarios + +### 1. Pause All SQL Pools in a Subscription +```powershell +.\pause_resume_synapse.ps1 -SubscriptionId "SubscriptionId" -ResourceGroups "*" -Action "Pause" +``` + +### 2. Resume SQL Pools for a Specific Project in Dev, Stg and Prod Environments +```powershell +.\pause_resume_synapse.ps1 -SubscriptionId "SubscriptionId" -Project "Project1" -DeploymentIds "Deployment1,Deployment2" -Environments "dev,stg,prod" -Action "Resume" +``` + +### 3. Test Without Making Changes +```powershell +.\pause_resume_synapse.ps1 -SubscriptionId "SubscriptionId" -ResourceGroups "*" -Action "Pause" -DryRun +``` + +--- + +## Prerequisites + +1. **Azure Subscription**: Ensure you have access to an Azure subscription. +2. **Azure PowerShell Module**: Ensure `Az.Accounts`, `Az.Sql`, `Az.Synapse`, `Az.Automation`, and `Az.Resources` modules are installed. Alternatively, use the `-InstallModules` parameter to install missing modules automatically. +3. **Required Azure Roles**: + - Assign the `Contributor` role to the Automation Account's managed identity for the scope `/subscriptions/`. + - Optionally, assign more restrictive permissions as needed (e.g., for specific Resource Groups). +4. **PowerShell Environment**: If running locally, ensure the account has appropriate permissions. + +--- + +## Local Execution + +To execute the script manually: + +1. Download the script (`pause_resume_synapse.ps1`) to your local machine. +2. Open PowerShell and navigate to the script's location. +3. Run the script with the desired parameters. Example: + + ```powershell + .\pause_resume_synapse.ps1 -SubscriptionId "" -ResourceGroups "" -Action "Pause" + ``` +4. Review the output for warnings, errors, or success messages. + +--- + +## Azure Automation Deployment +### 1. Create a Resource Group for Automation +To keep resources organized, create a dedicated Resource Group for the Automation Account: + +*Using Bash* +```bash +az group create --name "Automation-RG" --location "East US" +``` + +*Using PowerShell* +```powershell +New-AzResourceGroup -Name "Automation-RG" -Location "East US" +``` + +### 2. Create an Azure Automation Account + +*Using Bash* +```bash +az automation account create --resource-group "Automation-RG" --name "SynapseAutomation" --location "East US" +``` + +*Using PowerShell* +```powershell +New-AzAutomationAccount -ResourceGroupName "Automation-RG" -Name "SynapseAutomation" -Location "East US" +``` + +### 3. Enable System-Assigned Managed Identity + +*Using Bash* +```bash +az resource update --resource-group "Automation-RG" --name "SynapseAutomation" --resource-type "Microsoft.Automation/automationAccounts" --set identity.type=SystemAssigned +``` + +*Using PowerShell* +```powershell +Set-AzAutomationAccount -ResourceGroupName "Automation-RG" -Name "SynapseAutomation" -AssignSystemIdentity +``` + +### 4. Retrieve the Object ID of the Managed Identity + +*Using Bash* +```bash +az resource show --resource-group "Automation-RG" --name "SynapseAutomation" --resource-type "Microsoft.Automation/automationAccounts" --query "identity.principalId" --output tsv +``` + +*Using PowerShell* +```powershell +(Get-AzAutomationAccount -ResourceGroupName "Automation-RG" -Name "SynapseAutomation").Identity.PrincipalId +``` + +### 5. Assign Managed Identity Permissions +Grant the Managed Identity appropriate permissions: + +*Using Bash* +```bash +az role assignment create --assignee-object-id "" --role "Contributor" --scope "/subscriptions/" --assignee-principal-type "ServicePrincipal" +``` + +*Using PowerShell* +```powershell +New-AzRoleAssignment -ObjectId "" -RoleDefinitionName "Contributor" -Scope "/subscriptions/" +``` + +Replace "subscription-id" with your Azure subscription ID and "ManagedIdentityObjectId" with the output of the previous command. + +### 6. Import the Script into the Automation Account +This can be done directly in Azure Portal using the following steps: +1. In the Azure Portal, go to your Automation Account. +2. Navigate to Runbooks > Add a Runbook. +3. Upload the script and set its type to PowerShell. + +For a fully automated solution, follow these commands: + +1. Create the Runbook and Upload the script + + *Using Bash* + ```bash + az automation runbook create --resource-group "Automation-RG" --automation-account-name "SynapseAutomation" --name "PauseResumeSynapse" --type "PowerShell" + + az automation runbook replace-content --resource-group "Automation-RG" --automation-account-name "SynapseAutomation" --name "PauseResumeSynapse" --content @"./pause_resume_synapse.ps1" + ``` + + *Using PowerShell* + ```powershell + Import-AzAutomationRunbook -ResourceGroupName "Automation-RG" -AutomationAccountName "SynapseAutomation" -Name "PauseResumeSynapse" -Path "./pause_resume_synapse.ps1" -Type PowerShell + ``` + +2. Publish the Runbook + + *Using Bash* + ```bash + az automation runbook publish --resource-group "Automation-RG" --automation-account-name "SynapseAutomation" --name "PauseResumeSynapse" + ``` + + *Using PowerShell* + ```powershell + Publish-AzAutomationRunbook -ResourceGroupName "Automation-RG" -AutomationAccountName "SynapseAutomation" -Name "PauseResumeSynapse" + ``` + +### 7. Test the Runbook +1. Go to the Runbooks section of your Automation Account. +2. Select your uploaded Runbook. +3. Click Start and provide the necessary parameters. + +--- + +## Scheduling Automation + +To schedule the script in Azure Automation using Azure Portal: +1. Navigate to the Runbooks section of your Automation Account. +2. Select your Runbook. +3. Click Link to schedule. +4. Create a new schedule and configure it (e.g., daily at midnight). + +To schedule the Runbook using Commands: +1. Create a schedule in the Automation Account: + +*Using Bash* +```bash +# Calculate midnight for the next day in UTC -- or set manually to a specific time such as "2025-01-24T00:00:00Z" +$startTime = (Get-Date).AddDays(1).Date.ToUniversalTime() + +az automation schedule create --resource-group "Automation-RG" --automation-account-name "SynapseAutomation" --name "DailyPause" --start-time $startTime --time-zone UTC --frequency "Day" --interval 1 +``` + +*Using PowerShell* +```powershell +# Calculate midnight for the next day in UTC -- or set manually to a specific time such as "2025-01-24T00:00:00Z" +$startTime = (Get-Date).AddDays(1).Date.ToUniversalTime() + +New-AzAutomationSchedule ` + -ResourceGroupName "Automation-RG" ` + -AutomationAccountName "SynapseAutomation" ` + -Name "DailyPause" ` + -StartTime $startTime ` + -DayInterval 1 ` + -TimeZone "UTC" +``` + +2. Link the schedule to the Runbook: + After reviewing the [Azure CLI commands for Azure Automation](https://learn.microsoft.com/en-us/cli/azure/automation?view=azure-cli-latest), there is no direct Azure CLI command to link a schedule to a runbook. The ability to link a schedule to a runbook can only be done via the Azure Portal, PowerShell, or using the Azure REST API. + +*Using PowerShell* +```powershell +Register-AzAutomationScheduledRunbook ` + -AutomationAccountName "SynapseAutomation" ` + -ResourceGroupName "Automation-RG" ` + -RunbookName "PauseResumeSynapse" ` + -ScheduleName "DailyPause" ` + + # Add any relevant parameter based on your need + -Parameters @{ + #SubscriptionId = "SubscriptionId" + #DeploymentIds = "Deployment1,Deployment2" + #project = "ProjectName" + #Environments = "dev,stg,prod" + #ResourceGroups = "*" + #Action = "Pause" + } +``` + +--- + +## Logging and Monitoring + +1. **Error Logging**: + - Navigate to your Automation Account in the Azure Portal. + - Go to Jobs to view the status of Runbook executions. + - Check the logs for warnings, errors, or success messages. +2. **Error and Warning Counters**: + - The script tracks errors and warnings globally. + - The final log will show the total number of errors and warnings encountered. +3. **Dry Run**: + - Use the -DryRun flag to simulate actions without making any changes. + +--- + +## Troubleshooting + +- **Module Errors**: Ensure Azure modules are installed and updated: `Update-Module -Name Az -Force`. +- **Permission Issues**: Verify the Managed Identity has appropriate role assignments. Ensure local accounts have sufficient permissions. +- **Azure Automation Errors**: Review the Runbook job logs for detailed error messages. + +--- + +## Notes + +- **Dry Run Mode**: Use the `-DryRun` switch to verify actions before making changes. +- **Error and Warning Summary**: At the end of the script, a summary of errors and warnings is displayed. + +--- + +## References + +- [Pause and resume compute in dedicated SQL pool (formerly SQL DW) with Azure PowerShell](https://learn.microsoft.com/azure/synapse-analytics/sql-data-warehouse/pause-and-resume-compute-powershell) +- [Pause and Resume Compute in Synapse Workspace with PowerShell](https://learn.microsoft.com/azure/synapse-analytics/sql-data-warehouse/pause-and-resume-compute-workspace-powershell) +- [Azure Automation Overview](https://learn.microsoft.com/azure/automation/automation-intro) +- [Azure Automation Runbooks](https://learn.microsoft.com/azure/automation/automation-runbook-types) +- [Manage schedules in Azure Automation](https://learn.microsoft.com/azure/automation/shared-resources/schedules) +- [Using a system-assigned managed identity for an Azure Automation account](https://learn.microsoft.com/azure/automation/enable-managed-identity-for-automation) +- [Azure PowerShell Documentation](https://learn.microsoft.com/powershell/azure/new-azureps-module-az) +- [Azure CLI Documentation](https://learn.microsoft.com/cli/azure/) +- [Azure CLI Automation Commands](https://learn.microsoft.com/cli/azure/automation?view=azure-cli-latest) +- [Resume-AzSynapseSqlPool PowerShell Command](https://github.com/Azure/azure-powershell/blob/main/src/Synapse/Synapse/help/Resume-AzSynapseSqlPool.md) +- [Suspend-AzSynapseSqlPool PowerShell Command](https://github.com/Azure/azure-powershell/blob/main/src/Synapse/Synapse/help/Suspend-AzSynapseSqlPool.md) +- [Azure PowerShell GitHub Repository](https://github.com/Azure/azure-powershell/tree/main) +- [AZ.Automation PowerShell Commands](https://learn.microsoft.com/powershell/module/az.automation) +- [Azure Automation Pricing](https://azure.microsoft.com/pricing/details/automation/) + +--- + +## License + +This script is provided "as-is" without warranty of any kind. Use at your own risk. + +--- + +This Readme file provides a complete overview of how to use the script, deploy it to Azure Automation, set up permissions, and troubleshoot common issues. + diff --git a/e2e_samples/parking_sensors/utilities/pause_resume_synapse.ps1 b/e2e_samples/parking_sensors/utilities/pause_resume_synapse.ps1 new file mode 100755 index 000000000..7061537fa --- /dev/null +++ b/e2e_samples/parking_sensors/utilities/pause_resume_synapse.ps1 @@ -0,0 +1,302 @@ +# PowerShell script to Pause or Resume Azure Synapse SQL Pools and Azure SQL Data Warehouse (Dedicated SQL Pools). +# Supports both Azure Automation (Managed Identity) and local manual execution. + +param( + [string]$SubscriptionId, + [string]$DeploymentIds, + [string]$Project, + [string]$Environments = "dev,stg", + [string]$ResourceGroups, + [ValidateSet("Pause", "Resume")] + [string]$Action = "Pause", + [switch]$DryRun, + [switch]$InstallModules +) + +# Initialize error and warning tracking +[int]$global:iWarningCount = 0 +[int]$global:iErrorCount = 0 +$ErrorActionPreference = "Continue" + +# Function to log messages and handle error/warning counters +function Log-Message { + param ( + [string]$Message, + [string]$Level = "INFO" + ) + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + switch ($Level) { + "ERROR" { + $global:iErrorCount++ + Write-Error "$timestamp [$Level] $Message" + } + "WARNING" { + $global:iWarningCount++ + Write-Warning "$timestamp [$Level] $Message" + } + default { + Write-Output "$timestamp [$Level] $Message" + } + } +} + + +# Function to display usage +function Show-Usage { + Write-Host "Usage: .\pause_resume_synapse.ps1 -SubscriptionId [-DeploymentIds ] -Project -Environments `n[-ResourceGroups ] -Action [-DryRun] [-InstallModules]" -ForegroundColor Yellow + Write-Host " -SubscriptionId Azure Subscription ID (required for manual run)." + Write-Host " -ResourceGroups Resource groups (comma-separated, use '*' to target all resource groups)." + Write-Host " -DeploymentIds Deployment IDs for resource group generation. Specific to Databricks E2E use case. (comma-separated, required if ResourceGroups is not specified)." + Write-Host " -Project Project name for resource group generation. Specific to Databricks E2E use case. (required if ResourceGroups is not specified)." + Write-Host " -Environments Environments for resource group generation (comma-separated, required if ResourceGroups is not specified) (default: dev,stg)" + Write-Host " -Action Action to perform: Pause or Resume (default: Pause)." + Write-Host " -DryRun Simulate actions without making any changes (default: false)." + Write-Host " -InstallModules Install missing modules if not present (default: false)." + exit 1 +} + +# Trim unnecessary spaces from parameters +$SubscriptionId = $SubscriptionId.Trim() +$DeploymentIds = $DeploymentIds.Trim() +$Project = $Project.Trim() +$Environments = $Environments.Trim() +$ResourceGroups = $ResourceGroups.Trim() +$Action = $Action.Trim() + +# Validate Action parameter +if ($Action -notin @("Pause", "Resume")) { + Log-Message "ERROR: Invalid action '$Action'. Valid actions are 'Pause' or 'Resume'." "ERROR" + Show-Usage +} + +# Ensure Az modules are installed and imported +$modules = @("Az.Accounts", "Az.Sql", "Az.Synapse", "Az.Resources") +foreach ($module in $modules) { + if (-not (Get-Module -ListAvailable -Name $module)) { + if ($InstallModules) { + Log-Message "Installing module $module..." "INFO" + Install-Module -Name $module -Force -Scope CurrentUser -AllowClobber + } else { + Log-Message "Module $module is missing. Use -InstallModules to install missing modules." "ERROR" + exit 1 + } + } + Import-Module $module -ErrorAction Stop +} + +# Authenticate and set subscription context +try { + if ($env:MSI_SECRET) { + Log-Message "Running in Azure Automation. Authenticating with Managed Identity." "INFO" + Connect-AzAccount -Identity -ErrorAction Stop + } else { + Log-Message "Running locally. Using manual authentication." "INFO" + $Context = Get-AzContext + if (-not $Context) { + Log-Message "No existing context. Logging in..." "INFO" + Connect-AzAccount -ErrorAction Stop + } else { + Log-Message "Existing context detected. Account: $($Context.Account.Id)" "INFO" + } + } + + if (-not $SubscriptionId) { + $Subscriptions = Get-AzSubscription -ErrorAction Stop + if (-not $Subscriptions) { + Log-Message "No subscriptions are accessible." "ERROR" + Show-Usage + } + $SubscriptionId = $Subscriptions[0].Id + Log-Message "No subscription specified. Defaulting to: $SubscriptionId" "INFO" + } + + Set-AzContext -SubscriptionId $SubscriptionId -ErrorAction Stop + Log-Message "Subscription context set to: $SubscriptionId" "INFO" +} catch { + Log-Message "Authentication or subscription setup failed: $_" "ERROR" + Show-Usage +} + +# Determine resource groups +$ResourceGroupsList = @() + +if ($ResourceGroups -eq '*') { + try { + $ResourceGroupsList = Get-AzResourceGroup | Select-Object -ExpandProperty ResourceGroupName + Log-Message "Targeting all resource groups in the subscription." "INFO" + } catch { + Log-Message "Failed to retrieve resource groups: $_" "ERROR" + exit 1 + } +} elseif ($ResourceGroups -and $ResourceGroups -ne "") { + $ResourceGroupsList = $ResourceGroups -split ',' +} elseif ($Project -and $DeploymentIds) { + foreach ($env in $Environments -split ',') { + foreach ($deploymentId in $DeploymentIds -split ',') { + $ResourceGroupsList += "${Project}-${deploymentId}-dbw-${env}-rg" + $ResourceGroupsList += "${Project}-${deploymentId}-${env}-rg" + } + } +} else { + Log-Message "No resource groups provided or generated." "ERROR" + Show-Usage +} + +Log-Message "Resource Groups to process: $($ResourceGroupsList -join ', ')" "INFO" + +# Function to process Synapse SQL Pools +function Process-SynapseSqlPool { + param ( + [string]$ResourceGroup, + [string]$Action + ) + + try { + $workspaces = Get-AzSynapseWorkspace -ResourceGroupName $ResourceGroup | Select-Object -ExpandProperty Name + if (-not $workspaces) { + Log-Message "WARNING: No Synapse Workspaces found in Resource Group: $ResourceGroup" "WARNING" + return + } + } catch { + Log-Message "ERROR: Failed to retrieve Synapse Workspaces for Resource Group: $ResourceGroup. $_" "ERROR" + return + } + + foreach ($workspace in $workspaces) { + Log-Message "INFO: Checking Synapse Workspace: $workspace for SQL Pools" "INFO" + + try { + $sqlPools = Get-AzSynapseSqlPool -ResourceGroupName $ResourceGroup -WorkspaceName $workspace + if (-not $sqlPools) { + Log-Message "WARNING: No SQL Pools found in Workspace: $workspace" "WARNING" + continue + } + } catch { + Log-Message "ERROR: Failed to retrieve SQL Pools for Workspace: $workspace. $_" "ERROR" + continue + } + + foreach ($sqlPool in $sqlPools) { + $poolName = $sqlPool.Name + $poolStatus = $sqlPool.Status + + Log-Message "INFO: Current state of SQL Pool: $poolName is $poolStatus" "INFO" + if (($Action -eq "Pause" -and $poolStatus -eq "Paused") -or ($Action -eq "Resume" -and $poolStatus -eq "Online")) { + Log-Message "INFO: SQL Pool: $poolName is already in the desired state: $poolStatus. Skipping." "INFO" + } else { + Log-Message "INFO: SQL Pool: $poolName is in state: $poolStatus. Initiating $Action..." "INFO" + + try { + if (-not $DryRun) { + if ($Action -eq "Pause") { + Suspend-AzSynapseSqlPool -Name $poolName -WorkspaceName $workspace -ResourceGroupName $ResourceGroup + } elseif ($Action -eq "Resume") { + Resume-AzSynapseSqlPool -Name $poolName -WorkspaceName $workspace -ResourceGroupName $ResourceGroup + } + # Verify the new state + $newStatus = (Get-AzSynapseSqlPool -ResourceGroupName $ResourceGroup -WorkspaceName $workspace -Name $poolName).Status + Log-Message "INFO: New state of SQL Pool: $poolName is $newStatus" "INFO" + if (($Action -eq "Pause" -and $newStatus -eq "Paused") -or ($Action -eq "Resume" -and $newStatus -eq "Online")) { + Log-Message "Successfully $Action-ed SQL Pool: $poolName." "INFO" + } else { + Log-Message "ERROR: SQL Pool: $poolName did not transition to the expected state. Current state: $newStatus" "ERROR" + } + } + } catch { + Log-Message "ERROR: Failed to $Action SQL Pool: $poolName. $_" "ERROR" + } + } + } + } +} + +# Function to process Azure SQL Data Warehouses +function Process-SqlDatabase { + param ( + [string]$ResourceGroup, + [string]$Action + ) + + try { + $sqlServers = Get-AzSqlServer -ResourceGroupName $ResourceGroup | Select-Object -ExpandProperty ServerName + if (-not $sqlServers) { + Log-Message "WARNING: No SQL Servers found in Resource Group: $ResourceGroup" "WARNING" + return + } + } catch { + Log-Message "ERROR: Failed to retrieve SQL Servers for Resource Group: $ResourceGroup. $_" "ERROR" + return + } + + foreach ($server in $sqlServers) { + Log-Message "INFO: Checking SQL Server: $server in Resource Group: $ResourceGroup" "INFO" + + try { + $sqlDws = Get-AzSqlDatabase -ResourceGroupName $ResourceGroup -ServerName $server | Where-Object { $_.Edition -eq "DataWarehouse" } + if (-not $sqlDws) { + Log-Message "WARNING: No Dedicated SQL Pools found on Server: $server" "WARNING" + continue + } + } catch { + Log-Message "ERROR: Failed to retrieve Dedicated SQL Pools for Server: $server. $_" "ERROR" + continue + } + + foreach ($sqlDw in $sqlDws) { + $dwName = $sqlDw.DatabaseName + $dwStatus = $sqlDw.Status + + Log-Message "INFO: Current state of Dedicated SQL Pool: $dwName is $dwStatus" "INFO" + if (($Action -eq "Pause" -and $dwStatus -eq "Paused") -or ($Action -eq "Resume" -and $dwStatus -eq "Online")) { + Log-Message "INFO: Dedicated SQL Pool: $dwName is already in the desired state: $dwStatus. Skipping." "INFO" + } else { + Log-Message "INFO: Dedicated SQL Pool: $dwName is in state: $dwStatus. Initiating $Action..." "INFO" + + try { + if (-not $DryRun) { + if ($Action -eq "Pause") { + Suspend-AzSqlDatabase -ResourceGroupName $ResourceGroup -ServerName $server -DatabaseName $dwName + } elseif ($Action -eq "Resume") { + Resume-AzSqlDatabase -ResourceGroupName $ResourceGroup -ServerName $server -DatabaseName $dwName + } + # Verify the new state + $newStatus = (Get-AzSqlDatabase -ResourceGroupName $ResourceGroup -ServerName $server -DatabaseName $dwName).Status + Log-Message "INFO: New state of Dedicated SQL Pool: $dwName is $newStatus" "INFO" + if (($Action -eq "Pause" -and $newStatus -eq "Paused") -or ($Action -eq "Resume" -and $newStatus -eq "Online")) { + Log-Message "Successfully $Action-ed Dedicated SQL Pool: $dwName." "INFO" + } else { + Log-Message "ERROR: Dedicated SQL Pool: $dwName did not transition to the expected state. Current state: $newStatus" "ERROR" + } + } + } catch { + Log-Message "ERROR: Failed to $Action Dedicated SQL Pool: $dwName. $_" "ERROR" + } + } + } + } +} + +# Process each resource group +foreach ($resourceGroup in $ResourceGroupsList) { + try { + # Attempt to get the resource group with localized error handling + $rgExists = Get-AzResourceGroup -Name $resourceGroup -ErrorAction Stop + Log-Message "-----------------------------------------------" "INFO" + Log-Message "INFO: Processing Resource Group: $($rgExists.ResourceGroupName) in location: $($rgExists.Location)" "INFO" + Log-Message "-----------------------------------------------" "INFO" + + # Process Synapse SQL Pools + Process-SynapseSqlPool -ResourceGroup $resourceGroup -Action $Action + + # Process Azure SQL Data Warehouse + Process-SqlDatabase -ResourceGroup $resourceGroup -Action $Action + } catch { + # Log the error but don't exit the script + Log-Message "ERROR: Resource Group [$resourceGroup] does not exist or is inaccessible. $_" "ERROR" + continue + } +} + + +# Final error and warning summary +Log-Message "Script completed with $global:iErrorCount error(s) and $global:iWarningCount warning(s)." "INFO" \ No newline at end of file