executing uninstall string with powershell

Viewed 9145

I am trying to make a Powershell script for uninstalling software.

Here is the code:

$software = Read-Host "Software you want to remove"
$paths = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall', 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
Get-ChildItem $paths |
    Where-Object{ $_.GetValue('DisplayName') -match "$software" } |
    ForEach-Object{
        $uninstallString = $_.GetValue('UninstallString') + ' /quiet /norestart'
        Write-Host $uninstallString
        & "C:\Windows\SYSTEM32\cmd.exe" /c $uninstallString
    }

it works good for uninstall strings like

MsiExec.exe /X{C22F57FC-4B20-3354-8626-382E3C710B38} /quiet /norestart

But if I want to uninstall something like winrar which have uninstall strings like

C:\Program Files\WinRAR\uninstall.exe

I get the following error

cmd.exe : 'C:\Program' is not recognized as an internal or external command,

any idea please how to get this script working

Regards

2 Answers

The problem is that you're unconditionally appending /quiet /norestart.

The solution is to test if the uninstall string as a whole refers to an executable file:

$isExeOnly = Test-Path -LiteralPath $uninstallString

Based on that, you can decide how you want to handle such executables:

  • If you simply want to execute them without arguments:
$uninstallString = $_.GetValue('UninstallString')
$isExeOnly = Test-Path -LiteralPath $uninstallString
if (-not $isExeOnly) { $uninstallString += ' /quiet /norestart' } 
  • If you do want to pass arguments /quiet /norestart - though note that the target executable may refuse to execute if it doesn't understand these arguments:
$uninstallString = $_.GetValue('UninstallString')
$isExeOnly = Test-Path -LiteralPath $uninstallString
if ($isExeOnly) { $uninstallString = "`"$uninstallString`"" } 
$uninstallString += ' /quiet /norestart'

The alternative is to special-case the arguments (options) to pass based on the executable file name (Split-Path -Leaf $uninstallString), but that is obviously cumbersome and impossible to do comprehensively.

Uninstall-package works with msi installs.

For non-msi installs:

You'd have to find out the silent uninstall options for winrar. It might be '/S'. (A quick google says it is.)

get-package *winrar* | % { & $_.metadata['uninstallstring'] /S } 

Sometimes you have to get rid of literal double quotes:

get-package *winrar* | % { & ($_.metadata['uninstallstring'] -replace '"') /S } 

Here's an attempt of a general answer for non-msi installs where part of the uninstallstring may or may not be in double-quotes:

$uninstall = get-package whatever | % { $_.metadata['uninstallstring'] }
$prog, $myargs = $uninstall | select-string '("[^"]*"|\S)+' -AllMatches | 
  % matches | % value
$prog = $prog -replace '"',$null
$myargs += '/S'  # whatever silent uninstall option
& $prog $myargs
Related