Public/Uninstall-SqlServer.ps1

function Uninstall-SqlServer {

    <#
        .SYNOPSIS
            Uninstalls SQL Server completely from the system.

        .DESCRIPTION
            The Uninstall-SqlServer function removes SQL Server installation completely,
            including all instances, shared components, and registry entries.
            This is useful when SQL Server installation failed and left the system
            in a corrupted state that prevents new installations.

        .PARAMETER InstanceName
            Name of the SQL Server instance to uninstall. Default is MSSQLSERVER.

        .PARAMETER RemoveAllComponents
            Remove all SQL Server components including shared components.

        .PARAMETER Force
            Force removal even if some components cannot be uninstalled gracefully.

        .EXAMPLE
            Uninstall-SqlServer

            Uninstalls the default SQL Server instance (MSSQLSERVER).

        .EXAMPLE
            Uninstall-SqlServer -InstanceName "MYINSTANCE" -RemoveAllComponents

            Uninstalls the named instance and all shared components.

        .INPUTS
            None. You cannot pipe objects to Uninstall-SqlServer.

        .OUTPUTS
            [System.Boolean]
            Returns True if uninstallation was successful, otherwise False.

        .NOTES
            Used Functions:
                Name ║ Module/Namespace
                ═════════════════════════════════╬══════════════════════════════
                Get-WmiObject ║ Microsoft.PowerShell.Management
                Start-Process ║ Microsoft.PowerShell.Management
                Write-Verbose ║ Microsoft.PowerShell.Utility
                Write-Warning ║ Microsoft.PowerShell.Utility
                Get-FunctionDisplay ║ EguibarIT

        .NOTES
            Version: 1.0
            DateModified: 13/Aug/2025
            LastModifiedBy: Vicente Rodriguez Eguibar
                            vicente@eguibar.com
                            Eguibar IT
                            http://www.eguibarit.com

        .LINK
            https://github.com/vreguibar/EguibarIT/blob/main/Functions/Uninstall-SqlServer.ps1

        .COMPONENT
            SQL Server Management

        .ROLE
            Administrator

        .FUNCTIONALITY
            Removes SQL Server installations and components.
    #>


    [CmdletBinding(
        SupportsShouldProcess = $true,
        ConfirmImpact = 'High'
    )]
    [OutputType([System.Boolean])]

    param(
        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false,
            Position = 0,
            HelpMessage = 'SQL Server instance name to uninstall'
        )]
        [PSDefaultValue(
            Help = 'Default Value is "MSSQLSERVER"',
            Value = 'MSSQLSERVER'
        )]
        [String]
        $InstanceName = 'MSSQLSERVER',

        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false,
            HelpMessage = 'Remove all SQL Server components including shared components'
        )]
        [Switch]
        $RemoveAllComponents,

        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false,
            HelpMessage = 'Force removal even if some components fail to uninstall'
        )]
        [Switch]
        $Force
    )

    begin {
        Set-StrictMode -Version Latest

        # Display function header if variables exist
        if ($null -ne $Variables -and
            $null -ne $Variables.Header) {

            $txt = ($Variables.Header -f
                (Get-Date).ToString('dd/MMM/yyyy'),
                $MyInvocation.Mycommand,
                (Get-FunctionDisplay -Hashtable $PsBoundParameters -Verbose:$False)
            )
            Write-Verbose -Message $txt
        } #end if

        ##############################
        # Variables Definition

        [bool]$UninstallResult = $false
        [string]$StartTime = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')

    } #end begin

    process {

        try {
            Write-Verbose -Message ('Starting SQL Server uninstallation at {0}' -f $StartTime)

            # Check if SQL Server is installed
            Write-Verbose -Message 'Checking for SQL Server installations...'

            $SqlProducts = Get-WmiObject -Class Win32_Product | 
                Where-Object { $_.Name -like '*SQL Server*' }

            if (-not $SqlProducts) {
                Write-Warning -Message 'No SQL Server products found to uninstall.'
                return $true
            } #end if

            Write-Verbose -Message ('Found {0} SQL Server product(s) to uninstall' -f $SqlProducts.Count)

            foreach ($Product in $SqlProducts) {
                Write-Verbose -Message ('Found SQL Server product: {0} (Version: {1})' -f $Product.Name, $Product.Version)
            } #end foreach

            if ($PSCmdlet.ShouldProcess("SQL Server ($InstanceName)", 'Uninstall SQL Server')) {

                # Method 1: try using SQL Server setup.exe for clean uninstall
                Write-Verbose -Message 'Attempting clean uninstall using SQL Server setup...'

                $SetupPath = $null
                $PossiblePaths = @(
                    'C:\Program Files\Microsoft SQL Server\*\Setup Bootstrap\SQLServer*\setup.exe',
                    'D:\setup.exe'
                )

                foreach ($Path in $PossiblePaths) {
                    $FoundSetup = Get-ChildItem -Path $Path -ErrorAction SilentlyContinue | Select-Object -First 1
                    if ($FoundSetup) {
                        $SetupPath = $FoundSetup.FullName
                        Write-Verbose -Message ('Found SQL Server setup at: {0}' -f $SetupPath)
                        break
                    } #end if
                } #end foreach

                if ($SetupPath) {
                    Write-Verbose -Message 'Using SQL Server setup for uninstallation...'

                    $UninstallArgs = @(
                        '/Q',                                    # Silent uninstall
                        '/ACTION=Uninstall',                    # Uninstall action
                        '/FEATURES=SQL,AS,IS,MDS,Tools',        # Remove core features
                        '/INSTANCENAME={0}' -f $InstanceName    # Instance to remove
                    )

                    Write-Verbose -Message ('Uninstall arguments: {0}' -f ($UninstallArgs -join ' '))

                    $UninstallProcess = Start-Process -FilePath $SetupPath -ArgumentList $UninstallArgs -Wait -PassThru

                    if ($UninstallProcess.ExitCode -eq 0) {
                        Write-Verbose -Message 'SQL Server uninstalled successfully using setup.exe'
                        $UninstallResult = $true
                    } else {
                        Write-Warning -Message ('SQL Server setup uninstall failed with exit code: {0}' -f $UninstallProcess.ExitCode)
                        if (-not $Force) {
                            throw ('Setup uninstall failed with exit code: {0}' -f $UninstallProcess.ExitCode)
                        } #end if
                    } #end if-else
                } else {
                    Write-Warning -Message 'SQL Server setup.exe not found, trying alternative methods...'
                } #end if-else

                # Method 2: Use Windows Installer (MSI) to remove products
                if (-not $UninstallResult -or $RemoveAllComponents) {
                    Write-Verbose -Message 'Using Windows Installer to remove SQL Server products...'

                    foreach ($Product in $SqlProducts) {
                        Write-Verbose -Message ('Uninstalling {0}...' -f $Product.Name)

                        try {
                            $Result = $Product.Uninstall()
                            if ($Result.ReturnValue -eq 0) {
                                Write-Verbose -Message ('Successfully uninstalled {0}' -f $Product.Name)
                                $UninstallResult = $true
                            } else {
                                Write-Warning -Message ('Failed to uninstall {0}. return code: {1}' -f $Product.Name, $Result.ReturnValue)
                                if (-not $Force) {
                                    throw ('Failed to uninstall {0}' -f $Product.Name)
                                } #end if
                            } #end if-else
                        } catch {
                            Write-Warning -Message ('Error uninstalling {0}: {1}' -f $Product.Name, $_.Exception.Message)
                            if (-not $Force) {
                                throw
                            } #end if
                        } #end try-catch
                    } #end foreach
                } #end if

                # Method 3: Manual cleanup (registry and files)
                if ($Force -or $RemoveAllComponents) {
                    Write-Verbose -Message 'Performing manual cleanup of SQL Server remnants...'

                    # Stop SQL Server services
                    Write-Verbose -Message 'Stopping SQL Server services...'
                    $SqlServices = Get-Service | Where-Object { $_.Name -like '*SQL*' -and $_.Status -eq 'Running' }
                    foreach ($Service in $SqlServices) {
                        try {
                            Write-Verbose -Message ('Stopping service: {0}' -f $Service.Name)
                            Stop-Service -Name $Service.Name -Force -ErrorAction Stop
                        } catch {
                            Write-Warning -Message ('Failed to stop service {0}: {1}' -f $Service.Name, $_.Exception.Message)
                        } #end try-catch
                    } #end foreach

                    # Remove SQL Server directories
                    $SqlDirectories = @(
                        'C:\Program Files\Microsoft SQL Server',
                        'C:\Program Files (x86)\Microsoft SQL Server'
                    )

                    foreach ($Directory in $SqlDirectories) {
                        if (Test-Path -Path $Directory) {
                            Write-Verbose -Message ('Removing directory: {0}' -f $Directory)
                            try {
                                Remove-Item -Path $Directory -Recurse -Force -ErrorAction Stop
                                Write-Verbose -Message ('Successfully removed directory: {0}' -f $Directory)
                            } catch {
                                Write-Warning -Message ('Failed to remove directory {0}: {1}' -f $Directory, $_.Exception.Message)
                            } #end try-catch
                        } #end if
                    } #end foreach

                    Write-Verbose -Message 'Manual cleanup completed'
                    $UninstallResult = $true
                } #end if

            } #end if ShouldProcess

        } catch {
            Write-Error -Message ('Error during SQL Server uninstallation: {0}' -f $_.Exception.Message)
            $UninstallResult = $false
        } #end try-catch

    } #end process

    end {
        Write-Verbose -Message ('SQL Server uninstallation completed. Result: {0}' -f $UninstallResult)

        if ($UninstallResult) {
            Write-Host '✓ SQL Server uninstallation completed successfully!' -ForegroundColor Green
            Write-Host 'You can now proceed with a fresh SQL Server installation.' -ForegroundColor Yellow
        } else {
            Write-Warning -Message 'SQL Server uninstallation may not have completed successfully.'
            Write-Warning -Message 'Manual cleanup may be required before attempting reinstallation.'
        } #end if-else

        # Display function footer if variables exist
        if ($null -ne $Variables -and
            $null -ne $Variables.Footer) {

            $txt = ($Variables.Footer -f $MyInvocation.InvocationName,
                'uninstalling SQL Server components.'
            )
            Write-Verbose -Message $txt
        } #end if

        return $UninstallResult
    } #end end
} #end function Uninstall-SqlServer