Public/Invoke-mssRemoveDatabaseFromAvailabilityGroup.TempPoint.ps1

<#
.SYNOPSIS
Entfernt eine oder mehrere Datenbanken aus ihrer Always On-Verfügbarkeitsgruppe.
 
.DESCRIPTION
Die Funktion erkennt selbstständig, in welcher Verfügbarkeitsgruppe sich die angegebene
Datenbank befindet, entfernt sie daraus und löscht sie anschließend von allen sekundären
Replikaten. Systemdatenbanken werden ignoriert.
 
Wenn kein SqlInstance-Parameter angegeben wird, wird standardmäßig der aktuelle
Computername ($env:COMPUTERNAME) verwendet.
 
.PARAMETER SqlInstance
Die primäre SQL Server-Instanz (das primäre Replikat der AG).
Standard: aktueller Computername.
 
.PARAMETER SqlCredential
Alternative Anmeldeinformationen.
 
.PARAMETER Database
Name oder Array von Benutzerdatenbanken, die aus ihrer AG entfernt werden sollen.
Wird ignoriert, wenn -All gesetzt ist.
 
.PARAMETER All
Wenn gesetzt, werden alle Benutzerdatenbanken, die Mitglied einer AG sind, entfernt.
 
.PARAMETER EnableException
Schalter, um Ausnahmen durchzulassen.
 
.PARAMETER Confirm
Fordert vor kritischen Aktionen (Entfernen aus AG, Löschen auf Secondaries) eine Bestätigung an.
 
.PARAMETER WhatIf
Zeigt, was passieren würde, ohne Änderungen durchzuführen.
 
.EXAMPLE
# Einzelne Datenbank aus ihrer AG entfernen
Remove-mssDatabaseFromAvailabilityGroup -Database "SalesDB"
 
.EXAMPLE
# Alle AG-Datenbanken entfernen
Remove-mssDatabaseFromAvailabilityGroup -All
 
.NOTES
Erfordert dbatools und Invoke-mssLogging.
#>

function Remove-mssDatabaseFromAvailabilityGroup
{
    [CmdletBinding(DefaultParameterSetName = 'Specific', SupportsShouldProcess = $true, ConfirmImpact = 'None')]
    param (
        [Parameter(Mandatory = $false, Position = 0)]
        [string]$SqlInstance,
        [Parameter(Mandatory = $false)]
        [System.Management.Automation.PSCredential]$SqlCredential,
        [Parameter(Mandatory = $false, ParameterSetName = 'Specific')]
        [string[]]$Database,
        [Parameter(Mandatory = $false, ParameterSetName = 'All')]
        [switch]$All,
        [Parameter(Mandatory = $false)]
        [switch]$EnableException
    )
    
    begin
    {
        $functionName = $MyInvocation.MyCommand.Name
        if (-not $PSBoundParameters.ContainsKey('SqlInstance') -or [string]::IsNullOrWhiteSpace($SqlInstance))
        {
            $SqlInstance = $env:COMPUTERNAME
        }
        if (-not (Get-Module -ListAvailable -Name dbatools))
        {
            throw "dbatools-Modul nicht gefunden."
        }
        Invoke-mssLogging -Message "Starte $functionName auf $SqlInstance" -FunctionName $functionName -Level "INFO"
        $results = @()
    }
    
    process
    {
        try
        {
            # Alle Verfügbarkeitsgruppen abrufen
            $agParams = @{ SqlInstance = $SqlInstance; SqlCredential = $SqlCredential; ErrorAction = 'Stop' }
            if ($EnableException) { $agParams.EnableException = $true }
            $allAGs = Get-DbaAvailabilityGroup @agParams
            if (-not $allAGs)
            {
                Write-Warning "Keine Verfügbarkeitsgruppen auf $SqlInstance gefunden."
                return
            }
            
            # Zu entfernende Datenbanken ermitteln
            $targetDbs = @()
            if ($All)
            {
                Invoke-mssLogging -Message "Sammle alle Datenbanken, die in einer AG sind." -FunctionName $functionName -Level "INFO"
                foreach ($ag in $allAGs)
                {
                    $agDbs = Get-DbaAgDatabase -SqlInstance $SqlInstance -SqlCredential $SqlCredential -AvailabilityGroup $ag.Name -ErrorAction SilentlyContinue
                    $targetDbs += $agDbs | Select-Object -ExpandProperty Name
                }
                $targetDbs = $targetDbs | Select-Object -Unique
            }
            elseif ($Database)
            {
                $targetDbs = $Database
            }
            else
            {
                throw "Weder -All noch -Database angegeben."
            }
            
            if (-not $targetDbs)
            {
                Invoke-mssLogging -Message "Keine Datenbanken zum Entfernen gefunden." -FunctionName $functionName -Level "WARNING"
                return
            }
            
            # Für jede Datenbank die zugehörige AG finden und entfernen
            foreach ($dbName in $targetDbs)
            {
                # AG ermitteln, in der die DB Mitglied ist
                $agDb = Get-DbaAgDatabase -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $dbName -ErrorAction SilentlyContinue
                if (-not $agDb)
                {
                    $msg = "Datenbank '$dbName' ist in keiner Verfügbarkeitsgruppe (oder nicht vorhanden)."
                    Invoke-mssLogging -Message $msg -FunctionName $functionName -Level "WARNING"
                    $results += [PSCustomObject]@{
                        SqlInstance  = $SqlInstance
                        DatabaseName = $dbName
                        Status         = "NotInAG"
                        Message         = $msg
                    }
                    continue
                }
                $agName = $agDb.AvailabilityGroupName
                $secondaryInstances = $agDb | Get-DbaAgReplica -SqlInstance $SqlInstance -SqlCredential $SqlCredential | Where-Object { $_.Role -ne 'Primary' } | Select-Object -ExpandProperty Name
                
                # Entfernen aus AG
                $removeAction = "Datenbank '$dbName' aus AG '$agName' entfernen"
                if ($PSCmdlet.ShouldProcess($dbName, $removeAction))
                {
                    try
                    {
                        Invoke-mssLogging -Message $removeAction -FunctionName $functionName -Level "INFO"
                        Remove-DbaAgDatabase -SqlInstance $SqlInstance -SqlCredential $SqlCredential -AvailabilityGroup $agName -Database $dbName -Confirm:$false -ErrorAction Stop
                        $results += [PSCustomObject]@{
                            SqlInstance  = $SqlInstance
                            DatabaseName = $dbName
                            Status         = "RemovedFromAG"
                            Message         = "Erfolgreich aus AG '$agName' entfernt."
                        }
                    }
                    catch
                    {
                        $errMsg = "Fehler beim Entfernen aus AG: $($_.Exception.Message)"
                        Invoke-mssLogging -Message $errMsg -FunctionName $functionName -Level "ERROR"
                        if ($EnableException) { throw }
                        $results += [PSCustomObject]@{
                            SqlInstance  = $SqlInstance
                            DatabaseName = $dbName
                            Status         = "RemoveFromAGFailed"
                            Message         = $errMsg
                        }
                        continue
                    }
                }
                else
                {
                    $results += [PSCustomObject]@{ SqlInstance = $SqlInstance; DatabaseName = $dbName; Status = "RemoveSkipped"; Message = "WhatIf: Entfernen aus AG übersprungen." }
                    continue
                }
                
                # Löschen auf sekundären Replikaten
                foreach ($secondary in $secondaryInstances)
                {
                    $dropAction = "Datenbank '$dbName' auf sekundärem Knoten '$secondary' löschen"
                    if ($PSCmdlet.ShouldProcess($dbName, $dropAction))
                    {
                        try
                        {
                            Invoke-mssLogging -Message $dropAction -FunctionName $functionName -Level "INFO"
                            Remove-DbaDatabase -SqlInstance $secondary -SqlCredential $SqlCredential -Database $dbName -Confirm:$false -ErrorAction Stop
                            $results += [PSCustomObject]@{
                                SqlInstance  = $secondary
                                DatabaseName = $dbName
                                Status         = "DroppedOnSecondary"
                                Message         = "Datenbank auf '$secondary' gelöscht."
                            }
                        }
                        catch
                        {
                            $errMsg = "Fehler beim Löschen auf '$secondary': $($_.Exception.Message)"
                            Invoke-mssLogging -Message $errMsg -FunctionName $functionName -Level "ERROR"
                            if ($EnableException) { throw }
                            $results += [PSCustomObject]@{
                                SqlInstance  = $secondary
                                DatabaseName = $dbName
                                Status         = "DropOnSecondaryFailed"
                                Message         = $errMsg
                            }
                        }
                    }
                    else
                    {
                        $results += [PSCustomObject]@{ SqlInstance = $secondary; DatabaseName = $dbName; Status = "DropSkipped"; Message = "WhatIf: Löschen auf $secondary übersprungen." }
                    }
                }
            }
        }
        catch
        {
            $errMsg = "Allgemeiner Fehler: $($_.Exception.Message)"
            Invoke-mssLogging -Message $errMsg -FunctionName $functionName -Level "ERROR"
            if ($EnableException) { throw }
            $results += [PSCustomObject]@{ SqlInstance = $SqlInstance; DatabaseName = $null; Status = "GlobalError"; Message = $errMsg }
        }
    }
    
    end
    {
        Invoke-mssLogging -Message "$functionName abgeschlossen." -FunctionName $functionName -Level "INFO"
        return $results
    }
}