powershellfirefoxintunemicrosoft365-defender

PS Script to uninstall Firefox from multiple locations


I am working on creating a script to uninstall Firefox from multiple locations. I have a script that I've created and it works to an extent. I have made changes to my original script based on the answer below plus some other changes

$LocalUsers = (Get-ChildItem -Path "C:\Users").name

# Uninstalling from Program Files
if (Test-Path "${env:ProgramFiles(x86)}\Mozilla Firefox\uninstall\helper.exe"){
    Start-Process -FilePath "${env:ProgramFiles(x86)}\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
if (Test-Path "${env:ProgramFiles}\Mozilla Firefox\uninstall\helper.exe"){
    Start-Process -FilePath "${env:ProgramFiles}\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}

# Uninstalling for each user
ForEach ($LocalUser in $LocalUsers){
    $Userpath = "C:\Users\" + $LocalUser
    if (Test-Path "$Userpath\AppData\Local\Mozilla Firefox\uninstall\helper.exe"){
        Start-Process -FilePath "$Userpath\AppData\Local\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
    }

    Start-Sleep 20

    # Remove shortcuts from appdata
    Remove-Item -Path "$userpath\AppData\Local\Mozilla" -Force -Recurse -Verbose #-ErrorAction SilentlyContinue
    Remove-Item -Path "$userpath\AppData\LocalLow\Mozilla" -Force -Recurse -Verbose #-ErrorAction SilentlyContinue
    Remove-Item -Path "$userpath\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Firefox.lnk" -Force -Verbose #-ErrorAction SilentlyContinue
    Remove-Item -Path "$userpath\desktop\firefox.lnk" -Force -Verbose #-ErrorAction SilentlyContinue
}

# Remove related registry keys
$pathToRemove = @(
    'HKLM:\Software\Mozilla'
    'HKLM:\SOFTWARE\mozilla.org'
    'HKLM:\SOFTWARE\MozillaPlugins'
    'HKLM:\SOFTWARE\WOW6432Node\Mozilla'
    'HKLM:\SOFTWARE\WOW6432Node\mozilla.org'
    'HKLM:\SOFTWARE\WOW6432Node\MozillaPlugins'
    'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Firefox.lnk'
)

foreach($path in $pathToRemove) {
    if(Test-Path $path) {
        try {
            Remove-Item $path -Recurse -Force -Verbose #-ErrorAction SilentlyContinue
        }
        catch {
            Write-Warning $_.Exception.Message
        }
    }
}

The script has worked on some machines where it uninstalls the application, however, for others trace of it is being left behind in Windows Program Files. It is appearing as a dead link. I know it is a dead link because it is missing the Firefox logo. The strange thing is its points to %localappdata%\Mozilla Firefox\uninstall\helper.exe per the error

DealLink1 DeadLink2

Error 1 Error 2

What the app should look like if installed (ignoring the version just a screenshot from online):

ifinstalled


Solution

  • I'm assuming the problem is your chained if \ elseif \ else conditions, what could be happening is that if the first condition was $true you're only removing the first registry key and then exiting the chained conditions (this is by design):

    # only results in 'hello if' and then exits the chained conditions
    
    if($true) {
        'hello if'
    }
    elseif($true) {
        'hello elseif'
    }
    

    What you can do in this case is store all the paths in an array and then loop over them, testing if the path exists and, if it does, remove it:

    $pathToRemove = @(
        'HKLM:\Software\Mozilla'
        'HKLM:\SOFTWARE\mozilla.org'
        'HKLM:\SOFTWARE\MozillaPlugins'
        'HKLM:\SOFTWARE\WOW6432Node\Mozilla'
        'HKLM:\SOFTWARE\WOW6432Node\mozilla.org'
        'HKLM:\SOFTWARE\WOW6432Node\MozillaPlugins'
        'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Firefox.lnk'
    )
    
    foreach($path in $pathToRemove) {
        if(Test-Path $path) {
            try {
                Write-Verbose "Attempting to remove: $path" -Verbose
                Remove-Item $path -Recurse -Force
                Write-Verbose "Successfully removed: $path" -Verbose
            }
            catch {
                Write-Warning $_.Exception.Message
            }
        }
    }