1

I try to uninstall a msi file, but when I try this via array I get an error (cant find installation package)

When I do the same but not in array - it works

for ($i=0; $i -lt $msiArrayClean.length; $i++){
  
        Write-Host $msiArrayClean[$i]
        & msiexec.exe /x $msiArrayClean[$i]

}

here the output of Write Host

How i come to $msiArrayClean

 $msiCache = get-wmiobject Win32_Product | Where-Object Name -like "*7-Zip*"  | Format-Table LocalPackage -AutoSize -HideTableHeaders
    $msiString = $msiCache | Out-String
    $msiArrayWithEmptyLines = $msiString -split "`n"
    $msiArray = $msiArrayWithEmptyLines.Split('', [System.StringSplitOptions]::RemoveEmptyEntries)
    $msiArrayCleanString = $msiArray | Out-String
    $msiArrayClean = $msiArrayCleanString -split "`n"
0

2 Answers 2

1

A few caveats up front:

  • Format-* cmdlets output objects whose sole purpose is to provide formatting instructions to PowerShell's output-formatting system - see this answer. In short: only ever use Format-* cmdlets to format data for display, never for subsequent programmatic processing.

  • The CIM cmdlets (e.g., Get-CimInstance) superseded the WMI cmdlets (e.g., Get-WmiObject) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell (Core) (version 6 and above), where all future effort will go, doesn't even have them anymore. For more information, see this answer.

  • Use of the Win32_Product WMI class is discouraged, both for reasons of performance and due to potentially unwanted side effects - see this Microsoft article.

    • An alternative - available in Windows PowerShell only (not in PowerShell (Core) 7+) - is to use the following to get uninstall command lines and execute them via cmd /c:

      Get-Package -ProviderName Programs -IncludeWindowsInstaller | 
        ForEach-Object { $_.meta.attributes['UninstallString'] }
      

If you need to stick with Win32_Product:

# Get the MSI package paths of all installed products, where defined.
$msiCache = (Get-CimInstance Win32_Product).LocalPackage -ne $null

foreach ($msiPackagePath in $msiCache) {
  if (Test-Path -LiteralPath $msiPackagePath) {
    # Note that msiexec.exe runs *asynchronously*.
    # Use Start-Process -Wait to wait for each call to complete.
    & msiexec.exe /x $msiPackagePath
  } else {
    Write-Warning "Package not found: $msiPackagePath"
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1

I don't like reaching to WMI, since its perfomance is the issue. I prefer to do it via registry and it worked for me many times. Code explanation in comments.

$name = "7-zip"

#Get all items from registry
foreach ($obj in Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall") {
    #Get DisplayName property of registry
    $dname = $obj.GetValue("DisplayName")
    #Search for given name
    if ($dname -like "*$name*") {
        #Get uninstall string (it gets you msiexec /I{APPID})
        $uninstString = $obj.GetValue("UninstallString")
        foreach ($line in $uninstString) {
            #Getting GUID from "{" to "}""
            $found = $line -match '(\{.+\}).*'
            if ($found) {
                #If found - get GUID
                $appid = $matches[1]
                Write-Output "About to uninstall app $appid"
                #Start uninstallation
                Start-Process "msiexec.exe" -arg "/X $appid /qb" -Wait
            }
        }
    }
}

Edit: Added solution with msi path after Nehat's comment as this works for me (I tried to minimize the code :))

$msiCache = get-wmiobject Win32_Product | Where-Object Name -like "*7-Zip*"  | Format-Table LocalPackage -AutoSize -HideTableHeaders

foreach ($msi in $msiCache | Out-String) {
    if ([string]::IsNullOrEmpty($msi)) {
        continue
    }
    Write-Host $msi
    Start-Process "msiexec.exe" -arg "/x $msi" -Wait
}

2 Comments

Nice Solution, but in my case I need the Path to the cached msi File because : some APPs which are installed need the original MSI file when you want to uninstall - that's why I do it via wmi
Thanks you for your support: I get the same message (Installation Package could not be found - but its there ) - when you have some idea, please let me know - thanks for optimizing the code :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.