Remove-SnapAgent.psm1

function Remove-SnapAgent {
    <#
    .SYNOPSIS
        Completely removes Blackpoint SNAP Agent and ZTAC components from a Windows system.
 
    .DESCRIPTION
        This function removes all traces of Blackpoint SNAP Agent and ZTAC software including:
        - Running processes
        - Windows services
        - MSI installations
        - Program files and directories
        - Registry keys and entries
         
        The function performs a thorough cleanup by dynamically discovering installed versions
        and removing them via MSI uninstall, followed by manual cleanup of remaining artifacts.
 
    .EXAMPLE
        Remove-SnapAgent
         
        Performs a complete removal of SNAP Agent and ZTAC components.
 
    .NOTES
        Requires Administrator privileges to execute.
        Author: Dailen Gunter
         
    .LINK
        https://github.com/DailenG/Remove-SnapAgent
    #>

    
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param()

    #Requires -RunAsAdministrator

    $snapProcesses = @("SnapAgent", "snap", "snapw", "ztac")

    $snapFolders = @(
        "$env:ProgramFiles\Blackpoint\SNAP Agent",
        "$env:ProgramFiles(x86)\Blackpoint\SNAP Agent"
    )

    $ztacFolders = @(
        "$env:ProgramFiles\Blackpoint\ZTAC",
        "$env:ProgramFiles(x86)\Blackpoint\ZTAC"
    )

    $ztacServices = @("ZTAC", "ZtacFltr")

    # Stop any running processes
    Write-Host "Stopping any SNAP or ZTAC processes..." -ForegroundColor Green
    Get-Process $snapProcesses -ErrorAction SilentlyContinue | Stop-Process -Force

    # Stop and remove ZTAC services
    Write-Host "Stopping and removing ZTAC services..." -ForegroundColor Green
    foreach ($service in $ztacServices) {
        $svc = Get-Service $service -ErrorAction SilentlyContinue
        if ($svc) {
            try {
                if ($svc.Status -ne 'Stopped') {
                    Stop-Service $service -Force -ErrorAction Continue
                    Write-Host "Stopped service: $service" -ForegroundColor Green
                }
                # Use sc.exe to delete the service
                sc.exe delete $service
                Write-Host "Removed service: $service" -ForegroundColor Green
            } catch {
                Write-Warning "Failed to remove service: $service. Error: $_"
            }
        }
    }

    # Uninstall using MSI for all SnapAgent versions
    Write-Host "Uninstalling all SnapAgent versions via MSI..." -ForegroundColor Yellow
    $snapPackages = Get-Package -Name "SnapAgent" -ErrorAction SilentlyContinue
    if ($snapPackages) {
        $pkgCount = 0
        $totalPkgs = @($snapPackages).Count
        foreach ($pkg in $snapPackages) {
            $pkgCount++
            Write-Progress -Activity "Uninstalling SnapAgent packages" -Status "Processing $($pkg.Name) $($pkg.Version) ($pkgCount of $totalPkgs)" -PercentComplete (($pkgCount / $totalPkgs) * 100)
            Write-Host "Found SnapAgent version $($pkg.Version) - Uninstalling..." -ForegroundColor Yellow
            try {
                # Try using Uninstall-Package first
                Uninstall-Package -Name $pkg.Name -RequiredVersion $pkg.Version -Force -ErrorAction Stop
                Write-Host "Uninstalled SnapAgent $($pkg.Version)" -ForegroundColor Green
            } catch {
                Write-Host "Uninstall-Package failed for version $($pkg.Version) (expected, will try msiexec)" -ForegroundColor DarkGray
            }
        }
        Write-Progress -Activity "Uninstalling SnapAgent packages" -Completed
    }

    # Dynamically find and uninstall using msiexec with all SnapAgent GUIDs
    Write-Host "Searching for SnapAgent installations in registry..." -ForegroundColor Yellow
    $uninstallPaths = @(
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
        "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
    )

    $snapProducts = @()
    foreach ($path in $uninstallPaths) {
        $products = Get-ItemProperty $path -ErrorAction SilentlyContinue | 
            Where-Object { $_.DisplayName -like "*Snap*" -or $_.Publisher -like "*Blackpoint*" }
        $snapProducts += $products
    }

    if ($snapProducts) {
        foreach ($product in $snapProducts) {
            $guid = $product.PSChildName
            $name = $product.DisplayName
            $version = $product.DisplayVersion
            
            Write-Host "Found: $name $version (GUID: $guid)" -ForegroundColor Yellow
            Write-Host "Uninstalling via msiexec..." -ForegroundColor Yellow
            
            try {
                # Use msiexec for silent uninstall
                $uninstallArgs = "/x $guid /qn /norestart"
                $process = Start-Process "msiexec.exe" -ArgumentList $uninstallArgs -Wait -PassThru -NoNewWindow
                
                if ($process.ExitCode -eq 0) {
                    Write-Host "Successfully uninstalled: $name $version" -ForegroundColor Green
                } else {
                    Write-Warning "msiexec returned exit code $($process.ExitCode) for $name $version"
                }
            } catch {
                Write-Warning "Failed to uninstall $name $version via msiexec: $_"
            }
        }
    }

    # Uninstall ZTAC packages
    Write-Host "Removing any existing versions of ZTAC..." -ForegroundColor Green
    try {
        Uninstall-Package -Name "ZTAC" -AllVersions -Force -ErrorAction Stop
        Write-Host "Uninstalled ZTAC packages" -ForegroundColor Green
    } catch {
        Write-Host "No ZTAC packages found or uninstall failed (not critical)" -ForegroundColor DarkGray
    }

    # Remove folders
    Write-Host "Removing program directories..." -ForegroundColor Green
    foreach ($folder in $snapFolders + $ztacFolders) {
        if (Test-Path $folder) {
            try {
                Remove-Item -Path $folder -Recurse -Force
                Write-Host "Removed folder: $folder" -ForegroundColor Green
            } catch {
                Write-Warning "Failed to remove folder: $folder. Error: $_"
            }
        }
    }

    # Clean up registry keys
    Write-Host "Cleaning up registry keys..." -ForegroundColor Green

    # Build list of all discovered product GUIDs plus hardcoded known keys
    $registryKeys = @(
        "HKLM:\SOFTWARE\Classes\Installer\Features\0E1D3F0C2B974FA4AA0418F12B055384",
        "HKLM:\SOFTWARE\Classes\Installer\Products\0E1D3F0C2B974FA4AA0418F12B055384",
        "HKLM:\SOFTWARE\Classes\Installer\Products\0E1D3F0C2B974FA4AA0418F12B055384\SourceList",
        "HKLM:\SOFTWARE\Classes\Installer\Products\0E1D3F0C2B974FA4AA0418F12B055384\SourceList\Media",
        "HKLM:\SOFTWARE\Classes\Installer\Products\0E1D3F0C2B974FA4AA0418F12B055384\SourceList\Net",
        "HKLM:\SOFTWARE\Classes\Installer\UpgradeCodes\7CF0653F8B24F2647B3A70510A96BEE6",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes\7CF0653F8B24F2647B3A70510A96BEE6",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\08C8C87010175A141912F6695F06EB95",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\5E3D36BBC4ADCA749AC6CC3774478B04",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\74A044CACC826754BB48542EA5681E4C",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\A3129D8FE202CCF47B233E82C70367D2",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\A73F059633BC8314597EE7F81A662796",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\C0016A60CBED93E41900FCBD4BC10AB4",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\DB4ABEA1DA4832048BCCF78860ADA944",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\F1AB931B4E8A02A4F8E5F828409E4DD1",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\F81ECEA5C9A7CA3409D05D38A602B11C",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\0E1D3F0C2B974FA4AA0418F12B055384",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\0E1D3F0C2B974FA4AA0418F12B055384\Features",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\0E1D3F0C2B974FA4AA0418F12B055384\InstallProperties",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\0E1D3F0C2B974FA4AA0418F12B055384\Patches",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\0E1D3F0C2B974FA4AA0418F12B055384\Usage",
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C0F3D1E0-79B2-4AF4-AA40-811FB2503548}",
        "HKLM:\SYSTEM\CurrentControlSet\Services\ZTAC",
        "HKLM:\SYSTEM\CurrentControlSet\Services\ZtacFltr"
    )

    # Add registry keys for any discovered product GUIDs
    if ($snapProducts) {
        foreach ($product in $snapProducts) {
            $guid = $product.PSChildName
            $registryKeys += "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$guid"
            $registryKeys += "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$guid"
        }
    }

    $i = 0
    foreach ($key in $registryKeys) {
        Write-Progress -Activity "Cleaning up registry keys" -Status "Processing key $($i + 1) of $($registryKeys.Count)" -PercentComplete (($i / $registryKeys.Count) * 100)

        if (Test-Path $key) {
            try {
                Remove-Item -Path $key -Recurse -Force
                Write-Host "Removed registry key: $key" -ForegroundColor Green
            } catch {
                Write-Warning "Failed to remove registry key: $key. Error: $_"
            }
        }
        $i++
    }
    Write-Progress -Activity "Cleaning up registry keys" -Completed -Status "All registry keys processed."

    # Final verification
    Write-Host "`nVerifying cleanup..." -ForegroundColor Cyan
    $remainingPackages = Get-Package -Name "*Snap*" -ErrorAction SilentlyContinue
    if ($remainingPackages) {
        Write-Warning "The following packages are still installed:"
        $remainingPackages | Format-Table Name, Version, ProviderName
    } else {
        Write-Host "No SnapAgent packages found - cleanup successful!" -ForegroundColor Green
    }

    # Check for remaining folders
    $remainingFolders = $snapFolders + $ztacFolders | Where-Object { Test-Path $_ }
    if ($remainingFolders) {
        Write-Warning "The following folders still exist:"
        $remainingFolders | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow }
    } else {
        Write-Host "All program folders removed successfully!" -ForegroundColor Green
    }

    Write-Host "`nCleanup script completed!" -ForegroundColor Cyan
}

# Export the function
Export-ModuleMember -Function Remove-SnapAgent