public/Uninstall-Chocolatey.ps1

<#
.SYNOPSIS
Attempts to remove the Chocolatey Software form the system.

.DESCRIPTION
This command attempts to clean the system from the Chocolatey Software files.
It first look into the provided $InstallDir, or in the $Env:ChocolateyInstall if not provided.
If the $InstallDir provided is $null or empty, it will attempts to find the Chocolatey folder
from the choco.exe command path.
If no choco.exe is found under the $InstallDir, it will fail to uninstall.
This command also remove the $InstallDir from the Path.

.PARAMETER InstallDir
Installation Directory to remove Chocolatey from. Default looks up in $Env:ChocolateyInstall
Or, if specified with an empty/$null value, tries to find from the choco.exe path.

.EXAMPLE
Uninstall-Chocolatey -InstallDir ''
#Will uninstall Chocolatey from the location of Choco.exe if found from $Env:PATH

#>

function Uninstall-Chocolatey {
    [CmdletBinding(
        SupportsShouldProcess
    )]
    Param(
        [AllowNull()]
        [string]
        $InstallDir = $Env:ChocolateyInstall
    )

    process {
        #If InstallDir is empty or null, select from whee choco.exe is available
        
        if (-not $InstallDir) {
            Write-Debug "Attempting to find the choco.exe command."
            $chocoCmd = Get-Command 'choco.exe' -CommandType Application -ErrorAction SilentlyContinue
            #Install dir is where choco.exe is found minus \bin subfolder
            if (-not ($chocoCmd -and ($chocoBin = Split-Path -Parent $chocoCmd.Path -ErrorAction SilentlyContinue))) {
                Write-Warning "Could not find Chocolatey Software Install Folder"
                return
            }
            else {
                Write-Debug "Resolving $chocoBin\.."
                $InstallDir = (Resolve-Path ([io.path]::combine($chocoBin,'..'))).Path
            }
        }
        Write-Verbose "Chocolatey Installation Folder is $InstallDir"

        $chocoFiles = @('choco.exe','chocolatey.exe','cinst.exe','cuninst.exe','clist.exe','cpack.exe','cpush.exe',
        'cver.exe','cup.exe').Foreach{$_;"$_.old"} #ensure the .old are also removed
        
        #If Install dir does not have a choco.exe, do nothing as it could delete unwanted files
        if (
            [string]::IsNullOrEmpty($InstallDir) -or
            -not ((Test-Path $InstallDir) -and (Test-Path "$InstallDir\Choco.exe"))
             ) 
        {
            Write-Warning 'Chocolatey Installation Folder Not found'
            return
        }
        
        #all files under $InstallDir
        # Except those in $InstallDir\lib unless $_.Basename -in $chocoFiles
        # Except those in $installDir\bin unless $_.Basename -in $chocoFiles
        $FilesToRemove = Get-ChildItem $InstallDir -Recurse | Where-Object {
            -not (
                (
                    $_.FullName -match [regex]::escape([io.path]::combine($InstallDir,'lib')) -or
                    $_.FullName -match [regex]::escape([io.path]::combine($InstallDir,'bin'))
                ) -and
                $_.Name -notin $chocofiles
            )
        }

        Write-Debug ($FilesToRemove -join "`r`n>> ")
        
        if ($Pscmdlet.ShouldProcess('Chocofiles')) {
            $FilesToRemove | Sort-Object -Descending FullName | remove-item -Force -recurse -ErrorAction SilentlyContinue
        }

        Write-Verbose "Removing $InstallDir from the Path and the ChocolateyInstall Environment variable."
        [Environment]::SetEnvironmentVariable('ChocolateyInstall', $null, 'Machine')
        $Env:ChocolateyInstall = $null
        $AllPaths = [Environment]::GetEnvironmentVariable('Path','machine').split(';').where{
                        ![string]::IsNullOrEmpty($_) -and 
                        $_ -notmatch "^$([regex]::Escape($InstallDir))\\bin$"
                    } | Select-Object -unique
        
        Write-Debug 'Reset the machine Path without choco (and dedupe/no null)'
        Write-Debug ($AllPaths |Format-Table | Out-String)
        [Environment]::SetEnvironmentVariable('Path', ($AllPaths -Join ';'), 'Machine')

        #refresh after uninstall
        $envPath = [Environment]::GetEnvironmentVariable('Path','Machine')   
        [Environment]::SetEnvironmentVariable($EnvPath,'process')
        Write-Verbose 'Unistallation complete'
    }
}