modules/HomeLab.UI/Public/Handlers/3-VpnGatewayHandler.ps1

<#
.SYNOPSIS
    VPN Gateway Menu Handler for HomeLab Setup
.DESCRIPTION
    Processes user selections in the VPN gateway menu using the new modular configuration
    and UI helpers. Options include checking gateway status, generating VPN client configuration,
    uploading certificates, and removing certificates.
.PARAMETER ShowProgress
    If specified, shows a progress bar while loading the menu and performing operations.
.EXAMPLE
    Invoke-VpnGatewayMenu
.EXAMPLE
    Invoke-VpnGatewayMenu -ShowProgress
.NOTES
    Author: Jurie Smit
    Date: March 8, 2025
#>

function Invoke-VpnGatewayMenu {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [switch]$ShowProgress
    )
    
    $selection = 0
    do {
        try {
            Show-VpnGatewayMenu -ShowProgress:$ShowProgress
        }
        catch {
            Write-Host "Error displaying VPN Gateway Menu: $_" -ForegroundColor Red
            break
        }
        
        $selection = Read-Host "Select an option"
        $config = Get-Configuration
        
        # Build resource names based on configuration
        $resourceGroup = "$($config.env)-$($config.loc)-rg-$($config.project)"
        $gatewayName   = "$($config.env)-$($config.loc)-vpng-$($config.project)"
        
        switch ($selection) {
            "1" {
                Write-Host "Checking VPN Gateway status..." -ForegroundColor Cyan
                
                if ($ShowProgress) {
                    # Create a progress task for checking gateway status
                    $task = Start-ProgressTask -Activity "Checking VPN Gateway Status" -TotalSteps 3 -ScriptBlock {
                        # Step 1: Connecting to Azure
                        $syncHash.Status = "Connecting to Azure..."
                        $syncHash.CurrentStep = 1
                        
                        # Step 2: Retrieving gateway information
                        $syncHash.Status = "Retrieving gateway information..."
                        $syncHash.CurrentStep = 2
                        
                        # Get the status
                        $status = az network vnet-gateway show --resource-group $resourceGroup --name $gatewayName --query "properties.provisioningState" -o tsv 2>$null
                        $exitCode = $LASTEXITCODE
                        
                        if ($exitCode -eq 0) {
                            # Step 3: Retrieving additional details
                            $syncHash.Status = "Retrieving additional details..."
                            $syncHash.CurrentStep = 3
                            
                            # Get additional details
                            $gatewayType = az network vnet-gateway show --resource-group $resourceGroup --name $gatewayName --query "gatewayType" -o tsv
                            $vpnType = az network vnet-gateway show --resource-group $resourceGroup --name $gatewayName --query "vpnType" -o tsv
                            $sku = az network vnet-gateway show --resource-group $resourceGroup --name $gatewayName --query "sku.name" -o tsv
                            
                            return @{
                                Success = $true
                                Status = $status
                                GatewayType = $gatewayType
                                VpnType = $vpnType
                                Sku = $sku
                            }
                        }
                        else {
                            return @{
                                Success = $false
                                ErrorMessage = "VPN Gateway not found or error retrieving status."
                            }
                        }
                    }
                    
                    $result = $task.Complete()
                    
                    if ($result.Success) {
                        Write-Host "VPN Gateway Status: $($result.Status)" -ForegroundColor Green
                        Write-Host "Gateway Type: $($result.GatewayType)" -ForegroundColor White
                        Write-Host "VPN Type: $($result.VpnType)" -ForegroundColor White
                        Write-Host "SKU: $($result.Sku)" -ForegroundColor White
                    }
                    else {
                        Write-Host $result.ErrorMessage -ForegroundColor Red
                    }
                }
                else {
                    # Original implementation without progress bar
                    $status = az network vnet-gateway show --resource-group $resourceGroup --name $gatewayName --query "properties.provisioningState" -o tsv 2>$null
                    
                    if ($LASTEXITCODE -eq 0) {
                        Write-Host "VPN Gateway Status: $status" -ForegroundColor Green
                        
                        # Get additional details
                        $gatewayType = az network vnet-gateway show --resource-group $resourceGroup --name $gatewayName --query "gatewayType" -o tsv
                        $vpnType = az network vnet-gateway show --resource-group $resourceGroup --name $gatewayName --query "vpnType" -o tsv
                        $sku = az network vnet-gateway show --resource-group $resourceGroup --name $gatewayName --query "sku.name" -o tsv
                        
                        Write-Host "Gateway Type: $gatewayType" -ForegroundColor White
                        Write-Host "VPN Type: $vpnType" -ForegroundColor White
                        Write-Host "SKU: $sku" -ForegroundColor White
                    }
                    else {
                        Write-Host "VPN Gateway not found or error retrieving status." -ForegroundColor Red
                    }
                }
                
                Pause
            }
            "2" {
                Write-Host "Generating VPN client configuration..." -ForegroundColor Cyan
                
                $outputPath = Join-Path -Path $PWD -ChildPath "vpnclientconfiguration.zip"
                
                if ($ShowProgress) {
                    # Create a progress task for generating client configuration
                    $task = Start-ProgressTask -Activity "Generating VPN Client Configuration" -TotalSteps 4 -ScriptBlock {
                        # Step 1: Checking for required functions
                        $syncHash.Status = "Checking for required functions..."
                        $syncHash.CurrentStep = 1
                        
                        $useFunction = Get-Command Get-VpnClientConfiguration -ErrorAction SilentlyContinue
                        
                        # Step 2: Connecting to Azure
                        $syncHash.Status = "Connecting to Azure..."
                        $syncHash.CurrentStep = 2
                        
                        # Step 3: Locating VPN Gateway
                        $syncHash.Status = "Locating VPN Gateway..."
                        $syncHash.CurrentStep = 3
                        
                        # Step 4: Generating configuration
                        $syncHash.Status = "Generating configuration..."
                        $syncHash.CurrentStep = 4
                        
                        if ($useFunction) {
                            try {
                                Get-VpnClientConfiguration -ResourceGroupName $resourceGroup -GatewayName $gatewayName -OutputPath $outputPath
                                return @{
                                    Success = $true
                                    OutputPath = $outputPath
                                    UsedFunction = $true
                                }
                            }
                            catch {
                                return @{
                                    Success = $false
                                    ErrorMessage = "Error generating VPN client configuration: $_"
                                    UsedFunction = $true
                                }
                            }
                        }
                        else {
                            # Fallback to direct Azure CLI command
                            $result = az network vnet-gateway vpn-client generate --resource-group $resourceGroup --name $gatewayName --output-path $outputPath
                            
                            if ($LASTEXITCODE -eq 0) {
                                return @{
                                    Success = $true
                                    OutputPath = $outputPath
                                    UsedFunction = $false
                                }
                            }
                            else {
                                return @{
                                    Success = $false
                                    ErrorMessage = "Failed to generate VPN client configuration."
                                    UsedFunction = $false
                                }
                            }
                        }
                    }
                    
                    $result = $task.Complete()
                    
                    if ($result.Success) {
                        Write-Host "VPN client configuration generated successfully at: $($result.OutputPath)" -ForegroundColor Green
                    }
                    else {
                        if (-not $result.UsedFunction) {
                            Write-Host "Function Get-VpnClientConfiguration not found. Make sure the required module is imported." -ForegroundColor Red
                            Write-Host "Attempted to use Azure CLI directly..." -ForegroundColor Yellow
                        }
                        Write-Host $result.ErrorMessage -ForegroundColor Red
                    }
                }
                else {
                    # Original implementation without progress bar
                    # Assuming Get-VpnClientConfiguration is defined in another module
                    if (Get-Command Get-VpnClientConfiguration -ErrorAction SilentlyContinue) {
                        Get-VpnClientConfiguration -ResourceGroupName $resourceGroup -GatewayName $gatewayName -OutputPath $outputPath
                    }
                    else {
                        Write-Host "Function Get-VpnClientConfiguration not found. Make sure the required module is imported." -ForegroundColor Red
                        
                        # Fallback to direct Azure CLI command
                        Write-Host "Attempting to use Azure CLI directly..." -ForegroundColor Yellow
                        $result = az network vnet-gateway vpn-client generate --resource-group $resourceGroup --name $gatewayName --output-path $outputPath
                        
                        if ($LASTEXITCODE -eq 0) {
                            Write-Host "VPN client configuration generated successfully at: $outputPath" -ForegroundColor Green
                        }
                        else {
                            Write-Host "Failed to generate VPN client configuration." -ForegroundColor Red
                        }
                    }
                }
                
                Pause
            }
            "3" {
                Write-Host "Uploading certificate to VPN Gateway..." -ForegroundColor Cyan
                $certName = "$($config.env)-$($config.project)-vpn-root"
                
                Write-Host "Select the Base64 encoded certificate file (.txt)..." -ForegroundColor Yellow
                $certFile = Read-Host "Enter path to certificate file"
                
                if (Test-Path $certFile) {
                    $certData = Get-Content $certFile -Raw
                    
                    if ($ShowProgress) {
                        # Create a progress task for uploading certificate
                        $task = Start-ProgressTask -Activity "Uploading Certificate to VPN Gateway" -TotalSteps 4 -ScriptBlock {
                            # Step 1: Checking for required functions
                            $syncHash.Status = "Checking for required functions..."
                            $syncHash.CurrentStep = 1
                            
                            $useFunction = Get-Command Add-VpnGatewayCertificate -ErrorAction SilentlyContinue
                            
                            # Step 2: Validating certificate data
                            $syncHash.Status = "Validating certificate data..."
                            $syncHash.CurrentStep = 2
                            
                            # Step 3: Connecting to Azure
                            $syncHash.Status = "Connecting to Azure..."
                            $syncHash.CurrentStep = 3
                            
                            # Step 4: Uploading certificate
                            $syncHash.Status = "Uploading certificate..."
                            $syncHash.CurrentStep = 4
                            
                            if ($useFunction) {
                                try {
                                    Add-VpnGatewayCertificate -ResourceGroupName $resourceGroup -GatewayName $gatewayName -CertificateName $certName -CertificateData $certData
                                    return @{
                                        Success = $true
                                        UsedFunction = $true
                                    }
                                }
                                catch {
                                    return @{
                                        Success = $false
                                        ErrorMessage = "Error uploading certificate: $_"
                                        UsedFunction = $true
                                    }
                                }
                            }
                            else {
                                # Fallback to direct Azure CLI command
                                $result = az network vnet-gateway root-cert create --resource-group $resourceGroup --gateway-name $gatewayName --name $certName --public-cert-data $certData
                                
                                if ($LASTEXITCODE -eq 0) {
                                    return @{
                                        Success = $true
                                        UsedFunction = $false
                                    }
                                }
                                else {
                                    return @{
                                        Success = $false
                                        ErrorMessage = "Failed to upload certificate."
                                        UsedFunction = $false
                                    }
                                }
                            }
                        }
                        
                        $result = $task.Complete()
                        
                        if ($result.Success) {
                            Write-Host "Certificate uploaded successfully." -ForegroundColor Green
                        }
                        else {
                            if (-not $result.UsedFunction) {
                                Write-Host "Function Add-VpnGatewayCertificate not found. Make sure the required module is imported." -ForegroundColor Red
                                Write-Host "Attempted to use Azure CLI directly..." -ForegroundColor Yellow
                            }
                            Write-Host $result.ErrorMessage -ForegroundColor Red
                        }
                    }
                    else {
                        # Original implementation without progress bar
                        # Assuming Add-VpnGatewayCertificate is defined in another module
                        if (Get-Command Add-VpnGatewayCertificate -ErrorAction SilentlyContinue) {
                            Add-VpnGatewayCertificate -ResourceGroupName $resourceGroup -GatewayName $gatewayName -CertificateName $certName -CertificateData $certData
                        }
                        else {
                            Write-Host "Function Add-VpnGatewayCertificate not found. Make sure the required module is imported." -ForegroundColor Red
                            
                            # Fallback to direct Azure CLI command
                            Write-Host "Attempting to use Azure CLI directly..." -ForegroundColor Yellow
                            $result = az network vnet-gateway root-cert create --resource-group $resourceGroup --gateway-name $gatewayName --name $certName --public-cert-data $certData
                            
                            if ($LASTEXITCODE -eq 0) {
                                Write-Host "Certificate uploaded successfully." -ForegroundColor Green
                            }
                            else {
                                Write-Host "Failed to upload certificate." -ForegroundColor Red
                            }
                        }
                    }
                }
                else {
                    Write-Host "Certificate file not found." -ForegroundColor Red
                }
                
                Pause
            }
            "4" {
                Write-Host "Removing certificate from VPN Gateway..." -ForegroundColor Cyan
                
                if ($ShowProgress) {
                    # Create a progress task for listing and removing certificates
                    $task = Start-ProgressTask -Activity "Managing VPN Gateway Certificates" -TotalSteps 3 -ScriptBlock {
                        # Step 1: Connecting to Azure
                        $syncHash.Status = "Connecting to Azure..."
                        $syncHash.CurrentStep = 1
                        
                        # Step 2: Listing certificates
                        $syncHash.Status = "Listing certificates..."
                        $syncHash.CurrentStep = 2
                        
                        $certs = az network vnet-gateway root-cert list --resource-group $resourceGroup --gateway-name $gatewayName --query "[].name" -o tsv
                        
                        return @{
                            Certificates = $certs
                        }
                    }
                    
                    $result = $task.Complete()
                    
                    Write-Host "Existing certificates:" -ForegroundColor Yellow
                    if ($result.Certificates) {
                        $result.Certificates -split "`n" | ForEach-Object { Write-Host "- $_" -ForegroundColor White }
                        
                        $certToRemove = Read-Host "Enter certificate name to remove"
                        
                        if (-not [string]::IsNullOrWhiteSpace($certToRemove)) {
                            # Create another progress task for removing the certificate
                            $removeTask = Start-ProgressTask -Activity "Removing Certificate" -TotalSteps 2 -ScriptBlock {
                                # Step 1: Connecting to Azure
                                $syncHash.Status = "Connecting to Azure..."
                                $syncHash.CurrentStep = 1
                                
                                # Step 2: Removing certificate
                                $syncHash.Status = "Removing certificate..."
                                $syncHash.CurrentStep = 2
                                
                                $result = az network vnet-gateway root-cert delete --resource-group $resourceGroup --gateway-name $gatewayName --name $certToRemove
                                
                                return @{
                                    Success = ($LASTEXITCODE -eq 0)
                                }
                            }
                            
                            $removeResult = $removeTask.Complete()
                            
                            if ($removeResult.Success) {
                                Write-Host "Certificate removed successfully." -ForegroundColor Green
                            }
                            else {
                                Write-Host "Failed to remove certificate." -ForegroundColor Red
                            }
                        }
                    }
                    else {
                        Write-Host "No certificates found." -ForegroundColor Yellow
                    }
                }
                else {
                    # Original implementation without progress bar
                    Write-Host "Existing certificates:" -ForegroundColor Yellow
                    $certs = az network vnet-gateway root-cert list --resource-group $resourceGroup --gateway-name $gatewayName --query "[].name" -o tsv
                    
                    if ($certs) {
                        $certs -split "`n" | ForEach-Object { Write-Host "- $_" -ForegroundColor White }
                        
                        $certToRemove = Read-Host "Enter certificate name to remove"
                        
                        if (-not [string]::IsNullOrWhiteSpace($certToRemove)) {
                            $result = az network vnet-gateway root-cert delete --resource-group $resourceGroup --gateway-name $gatewayName --name $certToRemove
                            
                            if ($LASTEXITCODE -eq 0) {
                                Write-Host "Certificate removed successfully." -ForegroundColor Green
                            }
                            else {
                                Write-Host "Failed to remove certificate." -ForegroundColor Red
                            }
                        }
                    }
                    else {
                        Write-Host "No certificates found." -ForegroundColor Yellow
                    }
                }
                
                Pause
            }    
            "5" {
                Invoke-ConfigureVpnSplitTunneling
            }
            "0" {
                # Return to main menu; do nothing.
            }
            default {
                Write-Host "Invalid option. Please try again." -ForegroundColor Red
                Start-Sleep -Seconds 2
            }
        }
    } while ($selection -ne "0")
}