Uninstall Software En Masse

Uninstall Software En Masse

Every now and then, you may have the need to uninstall software, not just a single version but all versions of a certain product from your systems; e.g., QuickTime or Adobe Reader. Because these products are common components, you may have many different versions installed across your organization and because of these many different versions, you can’t just use a single command-line to uninstall them all.

Win32_Product

You may see in various forums, blog posts, etc. the recommendation to use something like this:

wmic product where (name="Adobe Reader") call uninstall

Please don’t do this. The Win32_Product class, which this wmic command-line is using, is evil. See Win32_Product Is Evil and Why Win32_Product is Bad News!  for details. Another problem with doing this is that it only works for Windows Installer installations.

The Solution to Uninstall Software En Masse

So how can we address this challenge? Create a script of course.

The uninstall software script I created (still VBScript to account for those systems still without PowerShell) does the following:

  • Searches through the Uninstall key in the registry (both 32-bit and 64-bit on 64-bit OSes).
  • Finds and loops through entries by DisplayName that contain a specified substring.
    • Grabs the Uninstall string from the entry.
    • Fixes up the uninstall string if needed.
      • Replaces /I with /X.
      • Adds /q if it’s not there already.
      • Adds /norestart if it’s not there already.
    • Runs the fixed up uninstall string to uninstall the product [optional].
  • Outputs the number of matching products found to the console/stdout.
  • Runs a hardware inventory [optional]
  • Creates (or appends to) a log file (called Uninstall-Software.log) in the temp directory of the user running the script or the ConfigMgr logs folder if the ConfigMgr agent is detected.

Usage

The uninstall software script presented here takes one parameter (without which the script does almost nothing):

  • /product:”<substring to search for>”

There are also two optional switches

  • /uninstall — if specified actually runs the uninstall string
  • /hwinv — if specified (and the ConfigMgr agent is installed on the system) runs a hardware inventory at the end

For testing purposes, simply don’t specify the uninstall switch. This will cause the log entries to be output to the console in addition to the log file.

If you need to modify the uninstall string fix-ups applied, simply edit the FixupUninstallString subroutine that starts on line 175.

Examples

The following are examples successfully used in a large production environment and deployed using a package and program in ConfigMgr CB (1602):

  • cscript.exe Uninstall-Software.vbs /product:"Adobe Reader" /uninstall
  • cscript.exe Uninstall-Software.vbs /product:"Adobe Acrobat Reader" /uninstall
  • cscript.exe Uninstall-Software.vbs /product:"Quicktime" /uninstall

Using in an Application

You can also use this script in an application by using the following guidelines:

  • Create the application and a deployment type.
  • Specifying one of the above command lines as the Uninstall command line in the deployment type.
  • Use a noop for the install command line, something like the following:

cmd /c echo .

  • Set the detection method to run the script changing the lines in the script as if it were a compliance item (see below and the comments in the script itself for this).
  • Deploy as an Uninstall optionally hiding it from the Software Center completely (as it would look awkward to the user if they see it there).

Using in Compliance Settings

It is also possible to use this script in a compliance item — you will have to increase the compliance item timeout however for it to successfully uninstall anything (https://blogs.msdn.microsoft.com/fei_xias_blog/2013/10/20/system-center-2012-configmgr-using-vbs-to-extend-the-dcm-script-execution-timeout-value/).

To do use the uninstall software script in this way, first modify lines 64, and 66-68. This is because we can’t pass parameters to scripts used in compliance items. Then use the script as both the detection and remediation script in the compliance item (each modified slightly differently per the notes in the script itself). Configure the setting check to check for a value equal to zero for the item to be compliant as anything else is non-compliant and that’s when we want the remediation script to kick in.

Uninstall Software Script (v 1.02)
The Unspoken Upgrade Requirement

Next Article

The Unspoken Upgrade Requirement

48 Comments

Cancel

  1. Hey Jason, would it be beneficial to add /qn instead of just /q? I have seen some poorly written uninstallers still display an interactive UI with just /q.

    • Could be — it’s all very installer/uninstaller specific. Easy enough to modify as noted in the post.

  2. Hello,

    Nice script but any time I try to use the /uninstall switch I get “Wrong number of arguments or invalid property assignment ‘WriteLogMsg’ ”
    Erro on linve 154, 6

    “WriteLogMsg MSG_RUNNING_UNINSTALL
    returnCode = g_WshShell.Run (sUninstallString, 0, true)

    • DOH. As they say, all code has bugs and you just found one – Thank You. This one is a typo on my part because of the logging I added and didn’t test that code branch. It’s fixed now, please re-download.

  3. Hello,

    Thank You- in line 155 you put “WriteLogMsg MSG_RUNNING_UNINSTALL 1, g_echoLog”
    But ut should be “WriteLogMsg MSG_RUNNING_UNINSTALL, 1, g_echoLog”

    Otherwise you get “Expected end of statement”

    Great Script by the way.

  4. Although you mention ‘deployed using a package and program in ConfigMgr CB (1602)’ I take it that it’s no different if the package ws deployed by ConfigMgr 2012 R2?

  5. Hello,
    Because of adding the v1.02 comment on line 8 the next comment lines are wrong now:
    ‘ Uncomment line 65 (do not modify it)
    ‘ Uncomment lines 67-69 and modfy as needed
    ‘ Comment out lines 50-58
    They should be:
    ‘ Uncomment line 66 (do not modify it)
    ‘ Uncomment lines 68-70 and modify as needed
    ‘ Comment out lines 51-58
    But thanks for the script.

    • Yep — whenever I add comments to the header, any internal comments referencing line numbers need to be adjusted. Maybe I need a better way to indicate what to change in the script.

  6. Anyone tried using this for Java? It seems to work perfectly, but then when I try and launch any site that uses Java, Internet Explorer immediately encounters a problem and has to close. This is IE11 on Windows 10.

    • I can’t say I’ve tried and don’t really know what would explain this behavior other than the normal stupid Java tricks.

    • I guess if you’re using it for Java (I do) be sure to close any browsers before uninstalling/ installing or you will end up with broken Java, it’s the usual Java quirks.

      • Correct. That’s something the uninstaller should take care of for you because that’s application specific.

  7. assuming purpose is to remove silently then why not advertise that this script can only work for MSI by design ?

    any applications not packaged as MSI will still be removed with their initial uninstallstring which is most lilely not silent

    • Because that’s not correct. The script includes logic to add silent or unattended switches to the command-line. There’s no one universal silent switch though so there’s no way for me to magically account for them all but it is a simple matter for anyone to modify the script slightly to add the necessary switches for whatever software that they are trying to uninstall.

  8. Jason, First off thanks for putting this together as I use it all the time.

    Ran into an issue with a program where it called an executable in the uninstall string, but had a space in the path so I would always get “file not found” when executing the script. My VB skills aren’t great so there might be a cleaner way of doing this, but I added the lines below to the subroutine “FixupUninstallString” and works great. Hopefully it will help someone else. Thanks Tim

    Sub FixupUninstallString(ByRef uninstallString)
    dim uninstall

    If InStr(1, uninstallString,” “,1) Then
    uninstall = Split(uninstallString, “/”)
    uninstallString = Chr(34) & uninstall(0) & Chr(34) & “/” & uninstall(1)
    End If

    If InStr(1, uninstallString, “/I”, 1) Then
    uninstallString = Replace(uninstallString, “/I”, “/X”, 1, 1, 1)
    End If

    If InStr(1, uninstallString, “/q”, 1) = 0 Then
    uninstallString = uninstallString & ” /q”
    End If

    If InStr(1, uninstallString, “/NoRestart”, 1) = 0 Then
    uninstallString = uninstallString & ” /NoRestart”
    End If

    End Sub

  9. Jason,
    Can you assist a noob on how to actually run your script, first locally on my pc before creating a package in ConfMgr?

    Any help is greatly appreciated.

    • Not sure exactly what you are looking for here. It’s a simple VBScript that you generally would run from the command-prompt. The Examples section above cites a few examples of the command-line to use assuming that the script is in the current directory.

  10. Can this script be modified to uninstall ClickOnce applications? They’re not registered in Add/Remove Programs and are often required to be removed before an updated version is installed. Because of that, they’re virtually impossible to manage in CM. Any ideas?

    • It can be modified to anything you’d like it to do. I don’t know anything about uninstalling ClickOnce apps though. I thought the whole point of CLickOnce was that they didn’t truly install though.

  11. Could this be used to uninstall Symantec Endpoint Protection 11 and 12? I’m having a huge problem removing Symantec’s software off of systems. Each site used to do it’s own IT now it’s been integrated into one group. We don’t have all the passwords to the old systems and they license has expired.

    • Sure. It can be used to uninstall anything that preoprly registers itself in add remove programs including an uninstall string. Nothing can really get you around not knowing thr password though — if it were that easy then having a password would be pretty meaningless in the first place.

  12. After testing this script it seems to work. I have been looking for a way to remove Office 2013 as I have ran into problems with most methods out there. I tried running it to remove Office 2013 and get a return “The language of this installation package is not supported by your system”. I did not receive this pop up while testing with Adobe Acrobat. Any suggestions?

    • That error message is from the uninstaller and has nothing to do with the script. The Acrobat uninstaller is completely different from the Office uninstaller so expecting the same message is a bad conclusion. You need to research uninstalling Office 2013 for the correct procedure to do so as what’s in add/remove programs may not be sufficient. Have you simply tried running that uninstall command line manually?

  13. Dave, why not use the offscrub to remove old Office versions? For 2013 msi you would use OffScrub_O15msi.vbs with arguements. Even if I use Uninstall-Software.vbs all the time I don’t think it’s the best for removing Office.

  14. Hello Jason!

    I don’t get the part when using global condition as a detection method. How do you do that ?

    As for me, a Global Condition is only usable in “Requirements” part. Maybe I’m misunderstanding something…

    Thanks for your explanation.

    • Yeah, good catch; I’m honestly not sure what my intention was there. That should totally refer to the requirement and not the detection method although you could also run the script as a detection method without creating a global condition. The detection method is probably what I was aiming for at the time I wrote this. I’ve updated that section above. Please let me know if this makes sense or if you have any problems.

  15. Thanks a lot for this – has just solved my Nitro PDF uninstall problem in SCCM!

    Do you have anything for the install process too ? I have a really sticky .exe InstallShield package that spawns a child process and causes SCCM to fail the installation (detect method failure because the installer exits early). I’ve tried wrapping it in a .BAT file using a timeout command to pause it, no joy. It’s really annoying! Any help would be appreciated.

    • You’re welcome.

      For the spawned process detection issue, the times I’ve run into this, a simple timeout was sufficient. How long is your timeout and have you validated that this is long enough for the spawned process to exit?

      The alternative to a timeout is to actually watch for the spawned process in your wrapper script and detect when it exits. This is non-trivial though.

  16. Hey Jason!

    Thank you for the awesome script. Only 2 small errors I can see in version 1.02, but they’re just eye candy anyway:

    Line 27: “Toal” should be “Total”

    Line 370: “\Logs” should be “Logs”

    I also had an executable in the uninstall string instead of an MSI, so I had to do a similar thing like Tim Amico to add quotes around the command:

    If InStr(1, uninstallString, “Uninstall.exe”, 1) Then
    uninstallString = Replace(uninstallString, uninstallString, ( “””” & uninstallString & “””” & ” /S” ), 1, 1, 1)
    End If

    Thanks again for such a helpful script!

    • Hi Christopher,

      Thank you for the updates and glad the script can help you.

  17. Dear Jason,

    I am unable to make this script work for me.
    I tried the same script without any editing with the command
    cscript.exe Uninstall-Software.vbs /product:”Adobe Air” /uninstall
    if I am using the script with /uninstall it gives message : system cannot find the file specified.
    If I use it with out /uninstall it finds the software but does not uninstall it.
    I have tried the same thing with many software with the same result.
    Please help.

    • It’s difficult to tell, but the command-line that you’ve posted above contains smart quotes instead of normal ascii quotes. This will always throw off command-lines. Can you confirm that the quotes are not smart quotes? Generally, copying and pasting into notepad will replace the smart quotes with normal ascii quotes.

  18. Jason, thank you so much for your work here.
    Is there away to search for just the title explicitly only as listed?

    We have a product named Box I do want to uninstall, but I don’t want to uninstall other product with Box in the display, like Box Tools, Box for Office, Mudbox, DropBox…

    • With the way the script is currently written, no, but you could easily modify line 158 to change the comparison operation so that it uses an exact match only. Alternatively, you could supply exclusion strings (using the /exclude parameter) to prevent those other products from being picked up. I would opt for the first option though (changing line 158).

  19. Jason, I don’t know whether the script can work for my situation or not, so I thought I’d ask the expert. I need to remove a slew of agents installed with Symantec/Altiris Management and Deployment software, which is NOT registered in Add/Remove Programs and so does not have a product name per se. I’ve run the script using /product:*altiris*, and it has only once found a single match. The majority of the time, it’s zeros for both architectures. SCCM hardware inventory returns a list of the agent executables under Installed Executable; can your script be easily modified to seek and destroy based on these rather than the product name parameter? Or should I stick with the partially successful bat file I’ve used thus far?

    Any suggestions would be greatly appreciated!

    Thanks!
    Carrie

    • The script looks specifically at Add/Remove Program information registered in the registry. Thus, if the application installation didn’t register anything there, the script won’t help.

  20. I really got my hopes up with this but unfortunately didn’t work for my purposes. It looks like no matter what Tomcat is determined to launch its gui whenever the uninstall.exe is launched, even with the /q. If anyone out there has figured out a way to silently uninstall Tomcat (the program, not the service) please please let me know!

    • Sorry, that’s not anything a script can overcome and is the result of the Tomcat uninstaller not being automation friendly.

  21. Hello Jason. Thank you for your script, it really helped me out. For anyone who’s interested, I was able to silently uninstall an .EXE package by identifying the alternative switch (“/VERY SILENT” in this case) and modifying the script as noted in the original post. I added an additional statement under “Sub FixupUninstallString(ByRef uninstallString)” as shown below:

    If InStr(1, uninstallString, “/VERYSILENT”, 1) = 0 Then
    uninstallString = uninstallString & ” /VERYSILENT”
    End If

    Worked great! Again, thank you for sharing.

  22. Are we able to run this script silent? I know it unistalls software silently, which works for me, but script itself displays 3 windows during uninstall, I would like to suppress that.

    • How are you running the script? ConfigMgr doesn’t display any UI to the interactive user by default.

      • thanks. I was running it by cscript.exe \\UNC\path\to\script.vbs /uninstall. It works, however it still displays one line that it created log file.

  23. I can run this script manually and it is working as expected. But I cannot make it work via GPO. I tried computer startup script, computer logon script, but it does nothing, how can I do it?

    • I don’t see why the script wouldn’t work as a system startup script but I’ve never tried to run it that way — it was created to be run from ConfigMgr. You may need to add some debugging to the script to figure out what’s not happening. The script does create it’s own log file though called uninstall-software.vbs.log in ConfigMgr client logs folder or the temp directory of the user running it which should be c:\Windows\Temp if run as a startup script.

      • I finally managed it to work, i put execution command cscript.exe \\UNC\path\to\script.vbs /uninstall into RunOnce registry key via GPO. So when computer is started, GPO injects this command into registry, it is then run, removes software and this registry key is automaticaly cleared afterwards. One thing which is not ideal, that it still displays command windows with one line of text, that script created log file, the window closes afterwards, but it is visible and doesnt look good for end user. So probably the only way would be edit the script not to display this line.