Powershell: AppReaper Script

This script will uninstall an application from a machine. It was originally written to remove the Ask Toolbar so it has a function in it to reset IE to defaults. It was deployed to machines via sccm. The script takes 4 inputs.

  1. Publisher
  2. DisplayName
  3. Parameters
  4. ResetIE

I would typically get the Publisher and DisplayName from the control panel of a test machine. Since this script was deployed via SCCM we wanted to do it silently in the background so the parameters input is required. For the Ask Toolbar I think it was just a /qn but you’ll need to test this out. The ResetIE parameter is set to false by default.

You can run this script from the command line like so: powershell.exe -executionpolicy bypass -file c:\pathtoscript\script.ps1 -Publisher Ask.com -DisplayName AskToolbar -Parameters /qn -ResetIE $false -Verbose *> c:\pathtolog\AppReaper.log.

[CmdletBinding()]
Param(
  [Parameter(Mandatory=$True,Position=1)]
   [string]$publisher,
	
   [Parameter(Mandatory=$True)]
   [string]$DisplayName,
   
   [Parameter(Mandatory=$True)]
   [string]$Parameters,

   [Parameter(Mandatory=$True)]
   [bool]$ResetIE
)

Write-Verbose "$(Get-Date) Publisher parameter: $publisher"
Write-Verbose "$(Get-Date) DisplayName parameter: $displayName"

Function Uninstall-MSI ($application, $params)
{
    $uninstallString = $application.UninstallString.ToLower().Replace("/i", "").Replace("msiexec.exe", "")
    Write-Verbose "$(Get-Date) Uninstall string: $params $uninstallString"
    Write-Verbose "$(Get-Date) Starting uninstall process..."
    $process = start-process "msiexec.exe" -arg "$params $uninstallString" -Wait -PassThru
    Uninstall-Status $application $process
}
Function Uninstall-EXE ($application, $params)
{
    Write-Verbose "$(Get-Date) Uninstall string: $params $(($application).UninstallString)"
    Write-Verbose "$(Get-Date) Starting uninstall process..."
    $process = start-process "$(($application).UninstallString)" -arg "$params" -Wait -PassThru
    Uninstall-Status $application $process
}
Function Uninstall-Status ($application, $procStatus)
{
    if($procStatus.ExitCode -eq 0)
    {
        Write-Verbose "$(Get-Date) $(($application).DisplayName) has been successfully uninstalled."
        if($ResetIE -eq $True)
        {
            Reset-InternetExplorer
        }
    }
    else
    {
        Write-Verbose "$(Get-Date) Uninstall failed with exit code: $($procStatus.ExitCode)."
    }
}
Function Reset-InternetExplorer
{
    Write-Verbose "$(Get-Date) Making a copy of Rundll32.exe"
    Copy-Item "c:\windows\system32\rundll32.exe" "c:\windows\system32\rundll32-low.exe"
    Write-Verbose "$(Get-Date) Setting rundll32.exe to low integrity level..."
    icacls "c:\windows\system32\rundll32-low.exe" /setintegritylevel low | out-null
    Kill-Process "Internet Explorer" "iexplore"
    Write-Verbose "$(Get-Date) Resetting Internet Explorer to defaults..."
    RunDll32.exe InetCpl.cpl,ClearMyTracksByProcess 4351
    Kill-Process "Low level rundll32" "rundll32-low"
}
Function Kill-Process ($app, $procName)
{
    Write-Verbose "$(Get-Date) Checking if $app is running..."
    $processes = get-process | Where {$_.ProcessName -like "*$procName*"}
    if($processes)
    {
        Write-Verbose "$(Get-Date) There are $(($processes).Count) $app processes running."
        Write-Verbose "$(Get-Date) $processes"
        Write-Verbose "$(Get-Date) Stopping processes..."
        $processes | Stop-Process -Force -PassThru -Confirm:$false -Verbose | out-null
    }
}

$architecture = $env:processor_architecture
if($architecture -eq "x86")
{
    $application_keys = Get-ChildItem 'hklm:\software\microsoft\windows\currentversion\uninstall\*' | % {Get-ItemProperty $_.pspath} | Where {$_.Publisher -like "$publisher*" -and $_.DisplayName -like "$DisplayName*"}
}
else
{
    $application_keys = Get-ChildItem 'hklm:\software\microsoft\windows\currentversion\uninstall\*','hklm:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' | % {Get-ItemProperty $_.pspath} | Where {$_.Publisher -like "$publisher*" -and $_.DisplayName -like "$DisplayName*"}
}
Write-Verbose "$(Get-Date) Searching the registry for installed applications..."

if($application_keys)
{
    Write-Verbose "$(Get-Date) Found $(($application_keys).count) application that matches the inputted parameters."
    Write-Verbose "$(Get-Date) Publisher: $(($application_keys).Publisher)"
    Write-Verbose "$(Get-Date) DisplayName: $(($application_keys).DisplayName)"
        
    if($(($application_keys).UninstallString) -like "msiexec.exe*")
    {
        Write-Verbose "$(Get-Date) Uninstall file type has been identified as msiexec..."
        Uninstall-MSI $application_keys $parameters
    }
    elseif($(($application_keys).UninstallString) -like "*.exe")
    {
        Write-Verbose "$(Get-Date) Uninstall file type has been identified as exe..."
        Uninstall-EXE $application_keys $parameters
    }
    else
    {
        Write-Verbose "$(Get-Date) ERROR: Unable to determine uninstall type..."
        exit
    }
}
else
{
    Write-Verbose "$(Get-Date) ERROR: Unable to locate displayname: $displayName by publisher: $publisher"
    exit
}
Write-Verbose "$(Get-Date) Exit..."