Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I am looking for assistance on making a bit of code more efficient. I currently have a simple Powershell script (part of a larger script) that enumerates items from a text file (namely the string used to identify an installed program) and then tries uninstalling each of those strings using msiexec:

$javaUninstall = Get-Content .\jre-uninstall-list.txt
    foreach ($java in $javaUninstall) {
    write-host "Trying", "$java"
    $app = Get-WmiObject -Class Win32_Product | Where-Object {
        $_.IdentifyingNumber -match "$java"
    &cmd /c "msiexec /uninstall $($app.IdentifyingNumber) /passive /quiet"

This code correctly uninstalls any version of 32-bit Java from Java 5 and on that is present on the system. However, it takes forever. Each item runs for 5-10 seconds - and then it moves on to the next. Is there any way to have it quickly skip over versions that are not found? Using a batch file this runs in under 15 seconds flat.

share|improve this question
I think part of your issue is you are invoking the command shell for each uninstall. Try executing msiexec directly. –  Keltari Apr 28 '14 at 13:55
So take the last line and change it to: msiexec /uninstall $($app.IdentifyingNumber) /passive /quiet ? –  Tim P. Apr 28 '14 at 14:18
Gave that a whirl. It still worked correctly, but there wasn't a great improvement in the execution time compared to the standard batch file. –  Tim P. Apr 28 '14 at 14:24
Should $_.IdentifyingNumber -match "$java" be $_.Name -match "$java"? Otherwise, if $java already contains the IdentifyingNumber, why would you query for it? –  Rynant Apr 28 '14 at 14:41
The $_.IdentifyingNumber piece actually represents something like this: {26A24AE4-039D-4CA4-87B4-2F83217055FF} - Name would be something like "Java 7 Update 55" - what this does is looks at the Win32_Product list and finds programs that match the IdentifyingNumbers listed in the text file instead of Name, as Name might end up with false positives. –  Tim P. Apr 28 '14 at 15:25

2 Answers 2

up vote 1 down vote accepted

Since the $java variable already contains the IdentifyingNumber, just use it directly with msiexec.

$javaUninstall = Get-Content .\jre-uninstall-list.txt
foreach ($java in $javaUninstall) {
    write-host "Trying", "$java"
    msiexec /uninstall $java /passive /quiet
share|improve this answer
This is a great find. I need to call cmd /c anyway though, as the process fails if more than one Java installation exists due to the fact that it doesn't wait. So I do a cmd /c START /WAIT... and so forth. I appreciate the help, this made it much faster. –  Tim P. Apr 28 '14 at 20:10
@Tim, can't you do Start-Process -Wait instead of calling cmd.exe? –  dangph Apr 29 '14 at 7:14

You could spin off each item in its own powershell instance. The solution I'm providing will likely be the most resource intensive (FYI). I don't want to take credit for another's work, so I'll link the script example provided HERE.

You'll could build the example into a function, and then iterate the function inside your foreach loop.

share|improve this answer
Only one MSI install/uninstall can be running at once. Spinning off separate instances would lead to collisions. –  EBGreen Apr 28 '14 at 15:57
@ebgreen not in windows 7 –  Colyn1337 Apr 28 '14 at 16:05

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.