windowspowershell

executing uninstall string with powershell


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


Solution

  • 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 -ErrorAction Ignore -LiteralPath $uninstallString
    

    Note: -ErrorAction Ignore ignores illegal characters in path errors that occur when a string with embedded " chars. is passed.

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

    $uninstallString = $_.GetValue('UninstallString')
    $isExeOnly = Test-Path -ErrorAction Ignore -LiteralPath $uninstallString
    if (-not $isExeOnly) { $uninstallString += ' /quiet /norestart' } 
    
    $uninstallString = $_.GetValue('UninstallString')
    $isExeOnly = Test-Path -ErrorAction Ignore -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.

    Then pass the resulting string to cmd /c for execution:

    cmd /c $uninstallString
    

    Note: