Uninstall Firefox from %appdata% user profile

hi,

what would be the best way to remove from user profile Firefox browser.

we have published ESR as company Firefox browser, but a lot of users when they tried in the past, did not have admin rights, and then when you install, it is moving to user profile, and now we need to get rid off from user profile very old version.

so far trying

#Remove from user folder
$UserDir = "C:\Users"
$Folders = Get-ChildItem -Path $UserDir
ForEach ($Folder in $Folders) 
{
	if (Test-Path "$Userdir\$folder\AppData\Local\Mozilla Firefox\uninstall\helper.exe")
	{ 
	Execute-Process -Path "$Userdir\$folder\AppData\Local\Mozilla Firefox\uninstall\helper.exe" -Parameters '-ms' -ContinueOnError $True
	}
}

Looks ok.

I’d be checking if the uninstall was successful and log it.

looks ok, but it is not removing, doing nothing :smiley:

I suspect your code may need to be run in the users context as the installation info may only exist within the users current registry or (less likely) there could be a permissions issue preventing it from being run.
But that would possibly require each user that has ever logged onto each machine to log on again so the script would work :thinking:
We have a 1:1 user to device ratio so each user only ever uses the one assigned device, so running a script like yours in the user context would usually be successful at resolving these kind of issues (Utilising Intune to deploy and execute the script) - But as a general rule we deploy all our software in the System Context and with tighter security policies prevent / request users not to install any software themselves.

As @That-Annoying-Guy suggested, I’d also recommend you add some logging to your code as a log of why it’s not working could help you solve the issue.
I’m unsure if this snippet is a standalone script or part of a PSADT deployment script, as how your script is run, can determine how best to do the logging.

Hey,

i know the Problem and i use a little function to remove user based installation.
Not really nice, but… May be it helps.

#region Function Remove-UserBasedInstallation
Function Remove-UserBasedInstallation {
<#
.SYNOPSIS
	Remove user based installation
.PARAMETER
    AppDisplayName (Name from add and remove programs)
    AppUninstallParameter (Onyl for EXE installation needed)
    IgnoreExitCodes (List the exit codes to ignore or * to ignore all exit codes. Only for EXE installation)
    ContinueOnError (Continue if an error is encountered. Default: $true)
.EXAMPLE
    Remove-UserBasedInstallation -AppDisplayName "Visual Code"
    Remove-UserBasedInstallation -AppDisplayName "Visual Code" -AppUninstallParameter "/S"
    Remove-UserBasedInstallation -AppDisplayName "Visual Code" -AppUninstallParameter "/S" -IgnoreExitCodes "1"
.NOTES
#>
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [string]$AppDisplayName,
        [Parameter(Mandatory=$false)]
        [ValidateNotNullorEmpty()]
        [string]$IgnoreExitCodes,
        [string]$AppUninstallParameter,
        [boolean]$ContinueOnError = $true
    )

 	Begin {
        ## Get the name of this function and write header
		[string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
		Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters -Header
 		$ErrorActionPreference = "Stop" 
        $FoundUserApp = $false
        [int32]$returnCode = 70031
    }

    Process {
        Write-Log -Message "Get user based installation [$AppDisplayName]." -Source $installPhase
        [PSObject[]]$UserProfiles = (Get-UserProfiles -ExcludeDefaultUser)
        ForEach($UserSID in $($UserProfiles.SID)) {
            $InstalledUserApps = Get-ChildItem -LiteralPath "Registry::HKEY_USERS\$($UserSID)\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" -Force -ErrorAction SilentlyContinue
            ForEach($UserApp in $InstalledUserApps) {
                $FoundUserApp = $false
                $UninstallItem = Split-Path -Path $UserApp -Leaf -ErrorAction SilentlyContinue
                $regGuid = "\{?(([0-9a-f]){8}-([0-9a-f]){4}-([0-9a-f]){4}-([0-9a-f]){4}-([0-9a-f]){12})\}?"
                $UserAppsPropertys = Get-ItemProperty -LiteralPath "Registry::$($UserApp)" -ErrorAction SilentlyContinue
                If (($UserAppsPropertys.DisplayName -eq $AppDisplayName) -and $UserAppsPropertys.UninstallString) {
                    $FoundUserApp = $true
                    Write-Log -Message "Found user installation." -Source $installPhase
                    If (($UninstallItem -match $regGuid) -and ($UserAppsPropertys.UninstallString -contains "msiexec.exe")) {
                        Write-Log -Message "Executing [$exeMsiexec /X $UninstallItem REBOOT=ReallySuppress /QN]..." -Source ${CmdletName}
                        $UnInstParam = "/x $UninstallItem REBOOT=ReallySuppress /qn"
                        $Process = Start-Process -FilePath $exeMsiexec -ArgumentList $UnInstParam -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
                        Wait-Process -InputObject $Process

                        If (($Process.ExitCode -eq 0) -or ($Process.ExitCode -eq 3010)) {
                            Write-Log -Message "Execution completed successfully with exit code [$($Process.ExitCode)]." -Source ${CmdletName}
                        } ElseIf ($Process.ExitCode -eq 1605) {
                            Write-Log -Message "Execution failed with exit code [$($Process.ExitCode)] because the product is not currently installed." -Severity 2 -Source ${CmdletName}
                        } Else {
                            If (-not $ContinueOnError) {
                                Write-Log -Message "Execution failed with exit code [$($Process.ExitCode)]." -Severity 3 -Source ${CmdletName}
                                Exit-Script -ExitCode $Process.ExitCode
                            }
                            Write-Log -Message "Execution failed with exit code [$($Process.ExitCode)], continue." -Severity 2 -Source ${CmdletName}
                        }

                    } Else {
                        If (-not $AppUninstallParameter) {
                            Write-Log -Message "No parameters were specified for the uninstallation." -Severity 3 -Source ${CmdletName}
                            Exit-Script -ExitCode $returnCode
                        }
                        If ($UserAppsPropertys.UninstallString.Contains('"')) {
                            $UninstallPath = [regex]::Match($UserAppsPropertys.UninstallString,'"(.*?)"').Groups[1].Value
                        }
                        If (Test-Path -Path $UninstallPath -PathType Leaf) {
                            Write-Log -Message "Executing [$UninstallPath $AppUninstallParameter]..." -Source ${CmdletName}
                            $Process = Start-Process -FilePath $UninstallPath -ArgumentList $AppUninstallParameter -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
                            Wait-Process -InputObject $Process

                            $ignoreExitCodeMatch = $false
                            If ($ignoreExitCodes) {
                                ## Check whether * was specified, which would tell us to ignore all exit codes
                                If ($ignoreExitCodes.Trim() -eq '*') {
                                    $ignoreExitCodeMatch = $true
                                } Else {
                                    ## Split the processes on a comma
                                    [Int32[]]$ignoreExitCodesArray = $ignoreExitCodes -split ','
                                    ForEach ($ignoreCode in $ignoreExitCodesArray) {
                                        If ($Process.ExitCode -eq $ignoreCode) {
                                            $ignoreExitCodeMatch = $true
                                        }
                                    }
                                }
                            }

                            If ($ignoreExitCodeMatch) {
                                Write-Log -Message "Execution completed and the exit code [$($Process.ExitCode)] is being ignored." -Source ${CmdletName}
                            } Else {
                                If (($Process.ExitCode -eq 0) -or ($Process.ExitCode -eq 3010)) {
                                    Write-Log -Message "Execution completed successfully with exit code [$($Process.ExitCode)]." -Source ${CmdletName}
                                } Else {
                                    If (-not $ContinueOnError) {
                                        Write-Log -Message "Execution failed with exit code [$($Process.ExitCode)]." -Severity 3 -Source ${CmdletName}
                                        Exit-Script -ExitCode $Process.ExitCode
                                    }
                                    Write-Log -Message "Execution failed with exit code [$($Process.ExitCode)], continue." -Severity 2 -Source ${CmdletName}
                                }
                            }
                        } Else {
                            Write-Log -Message "Remove executable not found." -Severity 2 -Source $installPhase  
                        }
                    }
                }
            }
        }

        If ($FoundUserApp -eq $false) {
            If (-not $ContinueOnError) {
                Write-Log -Message "User based installation not found, setting exit code to [$returnCode]." -Severity 3 -Source ${CmdletName}
                Exit-Script -ExitCode $returnCode
            }
            Write-Log -Message "User based installation not found." -Severity 2 -Source $installPhase
        }
    }

    End {
        Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -Footer
    }
}
#endregion
1 Like

Here’s what I have used in the past.

Uninstall system-based installation

    If ( Test-Path "$envProgramFiles\Mozilla Firefox\uninstall\helper.exe" ) {
        Write-log "=====> Firefox 64-bit detected"
        Execute-Process -Path "$envProgramFiles\Mozilla Firefox\uninstall\helper.exe" -Parameters "/S"
    }
    If ( Test-Path "$envProgramFilesx86\Mozilla Firefox\uninstall\helper.exe" ) {
        Write-log "=====> Firefox 32-bit detected"
        Execute-Process -Path "$envProgramFilesx86\Mozilla Firefox\uninstall\helper.exe" -Parameters "/S"
    }
    
    [String[]]$ProfilePaths = Get-UserProfiles | Select-Object -ExpandProperty 'ProfilePath'
    foreach ($item in $ProfilePaths ) {
        
        ## Checking for user-based installation and uninstalling
        If ( Test-Path "$item\AppData\Local\Mozilla Firefox\uninstall\helper.exe" ) {
            Write-log "=====> Firefox user-based installation detected in $item"
            Execute-Process -Path "$item\AppData\Local\Mozilla Firefox\uninstall\helper.exe" -Parameters "/S"
    
            #Clean-up user-based shortcuts
            $OneDriveFolder = 'OneDrive'
            Remove-File -Path "$item\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Firefox.lnk"
            Remove-File -Path "$item\Desktop\Firefox.lnk"
            Remove-File -Path "$item\$OneDriveFolder\Desktop\Firefox.lnk"
            Remove-Folder -Path "$item\AppData\Local\Mozilla Firefox"
        }

        ## Looping through each user registry and cleaning up user-based installation in programs and features
        [scriptblock]$HKCURegistrySettings = {
            $HKCUFirefox = Get-RegistryKey -Key 'HKCU\SOFTWARE\Mozilla\Mozilla Firefox' -SID $UserProfile.SID
            If ($HKCUFirefox -ne $null) { 
                Remove-RegistryKey -Key "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Mozilla Firefox $($HKCUFirefox.CurrentVersion)" -Recurse -SID $UserProfile.SID
            }
        }
        Invoke-HKCURegistrySettingsForAllUsers -RegistrySettings $HKCURegistrySettings
    }
1 Like