Public/Remove-FinOpsHub.ps1

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

<#
    .SYNOPSIS
    Delete a FinOps hub instance and optionally keep the storage account hosting cost data.
 
    .DESCRIPTION
    The Remove-FinOpsHub command deletes a FinOps Hub instance and optionally deletes the storage account hosting cost data.
 
    The command returns a boolean value indicating whether all resources were successfully deleted.
 
    .PARAMETER Name
    Required when specifying Name. Name of the FinOps Hub.
 
    .PARAMETER ResourceGroupName
    Optional when specifying Name. Resource Group Name for the FinOps Hub.
 
    .PARAMETER InputObject
    Required when specifying InputObject. Expected object is the output of Get-FinOpsHub.
 
    .PARAMETER KeepStorageAccount
    Optional. Indicates that the storage account associated with the FinOps Hub should be retained.
 
    .PARAMETER Force
    Optional. Deletes specified resources without asking for a confirmation.
 
    .EXAMPLE
    Remove-FinOpsHub -Name MyHub -ResourceGroupName MyRG -KeepStorageAccount
 
    Deletes a FinOps Hub named MyHub and deletes all associated resources except the storage account.
#>


function Remove-FinOpsHub
{
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'Name')]
        [ValidateNotNullOrEmpty()]
        [string]$Name,

        [Parameter(ParameterSetName = 'Name')]
        [string]$ResourceGroupName,

        [Parameter(Mandatory = $true, ParameterSetName = 'Object')]
        [ValidateNotNullOrEmpty()]
        [psobject]$InputObject,

        [Parameter(ParameterSetName = 'Name')]
        [Parameter(ParameterSetName = 'Object')]
        [switch]$KeepStorageAccount,
        
        [Parameter(ParameterSetName = 'Name')]
        [Parameter(ParameterSetName = 'Object')]
        [switch]$Force
    )

    $context = Get-AzContext
    if (-not $context)
    {
        throw $script:LocalizedData.Common_ContextNotFound
    }

    try
    {
        if ($PSCmdlet.ParameterSetName -eq 'Name')
        {
            if (-not [string]::IsNullOrEmpty($ResourceGroupName))
            {
                $hub = Get-FinOpsHub -Name $Name -ResourceGroupName $ResourceGroupName
            }
            else
            {
                $hub = Get-FinOpsHub -Name $Name
                $ResourceGroupName = $hub.Resources[0].ResourceGroupName
            }
        }
        else
        {
            $hub = $InputObject
            $Name = $hub.Name
            $ResourceGroupName = $hub.Resources[0].ResourceGroupName
        }

        if (-not $hub)
        {
            throw $script:LocalizedData.Hub_Remove_NotFound -f $Name
        }

        Write-Verbose -Message "Found FinOps Hub: $Name in resource group $ResourceGroupName"

        $uniqueId = Get-HubIdentifier -Collection $hub.Resources.Name
        
        $resources = Get-AzResource -ResourceGroupName $ResourceGroupName |
        Where-Object -FilterScript { $_.Name -like "*$uniqueId*" -and ((-not $KeepStorageAccount) -or $_.ResourceType -ne "Microsoft.Storage/storageAccounts") }
        Write-Verbose -Message "Filtered Resources: $($resources | ForEach-Object { $_.Name })"

        if ($null -eq $resources)
        {
            Write-Warning "No resources found to delete."
            return $false
        }

        # List all resources to be deleted
        Write-Host "The following resources will be deleted:"
        $resources | ForEach-Object { Write-Host "- $($_.ResourceId)" }

        # Prompt the user for confirmation
        if ($PSCmdlet.ShouldProcess($Name, 'DeleteFinOpsHub'))
        {
            # Initialize a flag to track if "Yes to All" was selected
            $yesToAll = $Force

            # Loop through each resource
            $success = $true
            foreach ($resource in $resources)
            {
                try
                {
                    # Skip confirmation if "Yes to All" was selected
                    if (-not $yesToAll)
                    {
                        $confirmation = $Host.UI.PromptForChoice(
                            "Confirm",
                            "Are you sure you want to delete the following resource:`n$($resource.ResourceId)",
                            @("&Yes", "Yes to &All", "&No", "No to A&ll", "&Suspend"),
                            0
                        )

                        # Handle the user's choice
                        switch ($confirmation)
                        {
                            0
                            {
                                # Yes
                                # Continue with deletion
                            }
                            1
                            {
                                # Yes to All
                                $yesToAll = $true
                            }
                            2
                            {
                                # No
                                Write-Verbose -Message "Skipping resource: $($resource.Name)"
                                continue
                            }
                            3
                            {
                                # No to All
                                Write-Verbose -Message "Skipping all resources."
                                return $false
                            }
                            4
                            {
                                # Suspend
                                Write-Verbose -Message "Operation suspended."
                                return $false
                            }
                        }
                    }

                    # Delete the resource
                    Write-Verbose -Message "Deleting resource: $($resource.Name)"
                    Remove-AzResource -ResourceId $resource.ResourceId -Force -ErrorAction Stop
                    Write-Host "Deleted resource: $($resource.Name)"
                }
                catch
                {
                    Write-Error -Message "Failed to delete resource: $($resource.Name). Error: $_"
                    $success = $false
                }
            }

            return $success
        }
    }
    catch
    {
        Write-Error -Message "Failed to remove FinOps hub. Error: $_"
        if ($_.Exception.InnerException)
        {
            throw "Detailed Error: $($_.Exception.InnerException.Message)"
        }
        else
        {
            throw "Detailed Error: $($_.Exception.Message)"
        }
    }
}