≡ Menu

Powershell: Uninstall software on remote computer

Ok. It’s time to uninstall a application using powershell. This post is continuation to Powershell: Script to query softwares installed on remote computer where I discussed about procedure to query installed applications on remote computer without using Win32_Product WMI class. The one advantage with Win32_Product WMI class is it’s uninstall() function using which we can trigger uninstallation of softwares on local or remote computer.

In this post, I am going to provide a powershell script which provides same functionality as uninstall() function of Win32_Product WMI class. My code uses GUID of product to trigger the uninstallation by passing it to msiexec process. It also triggers the uninstallation in silent mode so no UI will appear for the user while performing the uninstallation.

Code goes here…

[cmdletbinding()]            

param (            

 [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
 [string]$ComputerName = $env:computername,
 [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Mandatory=$true)]
 [string]$AppGUID
)            

 try {
  $returnval = ([WMICLASS]"\\$computerName\ROOT\CIMV2:win32_process").Create("msiexec `/x$AppGUID `/norestart `/qn")
 } catch {
  write-error "Failed to trigger the uninstallation. Review the error message"
  $_
  exit
 }
 switch ($($returnval.returnvalue)){
  0 { "Uninstallation command triggered successfully" }
  2 { "You don't have sufficient permissions to trigger the command on $Computer" }
  3 { "You don't have sufficient permissions to trigger the command on $Computer" }
  8 { "An unknown error has occurred" }
  9 { "Path Not Found" }
  9 { "Invalid Parameter"}
 }

Note that you need my previous script(Get-InstalledSoftware.ps1) and the one discussed in this article(Uninstall-InstalledSoftware.ps1) to make this uninstallation works since the code discussed in this article depends on the output of Get-InstalledSoftware.ps1 script.

Usage:

  1. Run Get-InstalledSoftware.ps1 script and note the GUID of application that you want to uninstall.
  2. Run Uninstall-InstalledSoftware.ps1 -GUID <<uninstall application GUID here>>

Uninstall-InstalledSoftware.ps1 -GUID “{54D3F6B5-515B-45B8-8F41-FC4D26FEFFEA}”

Test this script in test environment before you try on any production computer. Any improper use of this script can trigger the uninstallation of multiple applications if handled improperly.

This can made as single liner…..

.\Get-InstalledSoftware.ps1 -ComputerName MyPC1 | ? {$_.AppName -eq “iTunes” } | .\Uninstall-InstalledSoftware.ps1

This triggers the installation of iTunes applications. Please note that at any point of time you are passing the output single computer to Uninstall-InstalledSoftware.ps1.

This is just a initial version. I will enhance it to accept multiple computers and multiple uninstallations at same time. I will also make it more robust to track the uninstallation process.

Hope this helps..

Your comments are welcome

Comments on this entry are closed.

  • ducu March 22, 2012, 5:04 pm

    Hi Sitaram,

    Great work here you have done! I have seen that you posted a way to input a list of computers with the following command Get-Content c:\temp\computers.txt | Get-InstalledSoftware.ps1 but how would you you do do in a single line to extract from a list of computers a specific list of application that would than need to be uninstalled?

    • Sitaram Pamarthi March 22, 2012, 10:51 pm

      Ducu,
      If I understood your question correctly, you want to scan a list of computers to check if a application is installed or not and the computers list is available in text file.

      Assuming I am correct in understanding your requirement, you can do this by using below command.

      Get-Content c:\temp\Computers.txt | .\Get-InstalledSoftware.ps1 | Where {$_.AppName -match “iTunes” }

      If you want to trigger uninstallation as well, then extend the command like below.

      Get-Content c:\temp\Computers.txt | .\Get-InstalledSoftware.ps1 | Where {$_.AppName -match “iTunes” } | .\Uninstall-InstalledSoftware.ps1

      PS: I don’t have sophisticated lab to test out these things. So, please try in test bed against few test computers before pushing to production.

      Feel free to post questions if any have any.

  • ND June 19, 2012, 3:03 pm

    Hi

    Uninstall doesn`t work on window 2003/2008 server. It do says uninstalation triggred but doesn`t uninstall the software

    ND

    • Sitaram Pamarthi June 19, 2012, 8:38 pm

      ND,
      Please post the output of get-InstalledSoftware.ps1 output and the command you are using to uninstall the app. That will help me to analyze what went wrong.

  • ND June 21, 2012, 4:19 pm

    Get Install Command-

    .\Get-InstalledSoftware.ps1 | Where {$_.AppName -match “IBM Parity Client” } -verbose >Getsoft.txt

    OutPut –
    ComputerName : Computer name
    AppName : IBM Parity Client
    AppVersion : 2.40.04
    AppVendor : IBM
    InstalledDate : 20111122
    UninstallKey : “C:\Program Files (x86)\InstallShield Installation Information\{4B932CA6-727B-4948-91E3-FFCF75CE3478}\s
    etup.exe” -runfromtemp -l0x0009 -removeonly
    AppGUID : {4B932CA6-727B-4948-91E3-FFCF75CE3478}

    Uninstall command –
    .\Get-InstalledSoftware.ps1 | Where {$_.AppName –match “IBM Parity Client” } | .\Uninstall-InstalledSoftware.ps1

    OutPut
    Uninstallation command triggered successfully

    But Program IBM Parity Client doesn`t unistalled.

    I had 4 soltwares need uninstall from around 100 boxes.

    Thanks

    ND

  • Sitaram Pamarthi June 21, 2012, 4:28 pm

    Thanks ND. Now I understood the problem. My script is designed to uninstall MSI programs. But in your case, it seems to be a exe installation.

    However, you can get this work by changing the below line in Uninstall-InstalledSoftware.ps1…

    $returnval = ([WMICLASS]”\\$computerName\ROOT\CIMV2:win32_process”).Create(“msiexec `/x$AppGUID `/qn”)

    to…..

    $returnval = ([WMICLASS]”\\$computerName\ROOT\CIMV2:win32_process”).Create(“C:\Program Files (x86)\InstallShield Installation Information\{4B932CA6-727B-4948-91E3-FFCF75CE3478}\setup.exe -runfromtemp -l0x0009 -removeonly”)

    Try this and let me know how it goes…

    • Sam July 6, 2016, 11:49 am

      I tried this option but it too didn’t work. it gives and error [Path not found, Invalid Parameter]

      • Wintel Rocks July 9, 2016, 9:37 am

        sounds like the app has some issues with uninstallation. Have you tried doing it manually from Add/Remove Programs and is working fine?

  • ND June 22, 2012, 1:26 pm

    Hi
    Thanks lot, it does help.

    I had one more QUS if want uninstall multiple software (preferly one by one) Should I create multiple Uninstall-InstalledSoftware.ps1 files

    ND

    • Sitaram Pamarthi June 22, 2012, 4:27 pm

      ND, glad to that it is working. No need to create multiple scripts. We can accommodate everything in one place with minor modifications to the code. I will try to do that when I find some time. Email me(http://techibee.com/contact-us) if you are looking for this on urgent basis.

  • ATLDrake June 23, 2012, 12:24 am

    Thanks so much for this script, I do have a question though, how would I go about adding filtering, so that I could just pull one program as a -Filter “APPName” parameter? I’m relatively new to Powershell scripting, so any help would be fantastic!

  • Sitaram Pamarthi June 23, 2012, 12:41 am

    ATLDrake, you want to filter the output of Get-InstalledSoftware.ps1 by just providing -Filter “iTunes” ? you can pretty much do that. All you need to do is, declare $Filter as [string] type parameter and while adding the AppName object just check if AppName value is equal to the value of $Filter.

    Hope that helps..

    • ATLDrake June 23, 2012, 1:02 am

      Thanks! I got it to accept the filter and it works, but if I don’t supply an AppName it doesn’t return anything. The simple fix is I have 2 scripts, one that has the filter, one without, but that seems a little silly. I added
      “if($AppDisplayName -eq $filter) {”

      before

      “if(!AppDisplayName){continue} line”

  • Steve June 28, 2012, 2:56 am

    I’m fairly new to PowerShell scripting and I love the functionality of this script. I need to be able to use this script to uninstall two apps on our Win7 clients via Altiris. Is the below command correct to look for the app and then delete it from a local computer? I know I’d have to copy the .ps1 files locally, then execute this. Also, can I distribute this in a .bat file?

    .\Get-InstalledSoftware.ps1 | Where {$_.AppName -match “%Connect%” } | .\Uninstall-InstalledSoftware.ps1

    Thanks!

  • Jared Heinrichs June 29, 2012, 2:12 am

    I tried one more variation to the command:

    PS C:\powershell> .\Get-InstalledSoftware.ps1 -ComputerName computer01 | ? {$_.AppVendor -eq “Kaseya” } | .\Uninstall-Insta
    lledSoftware.ps1

    Again it says “Uninstallation command triggered successfully” but the program is never un-installed.

    This is being run against a fully patched Windows 7 machine from a fully patched windows 7 machine. I am a domain admin.

  • Tam July 18, 2012, 3:40 pm

    Hi There,

    Were trying to use this script to uninstall software from around 300 machines in our domain and are testing it in a lab environment.

    The results I am getting are that it only seems to run against one server at a time using the following command:

    Get-Content .\computers.txt | .\Get-InstalledSoftware.ps1 | Where {$_.AppName -match “My Application” } | .\Uninstall-InstalledSoftware.ps1

    From previous threads it was mentioned this technique could be used to not only to retrieve the list of installed software on multiple machines but also to trigger the uninstallation.

    Any chance of helping us to find out why this does not move to the next machine? Also have you managed to get any tracing / logging of the uninstall process going, I think this would help me figure out what is going wrong.

    Thanks!

    • Sitaram Pamarthi July 18, 2012, 4:03 pm

      Tam, The current version of the script in post is not educated to accept multiple things from pipeline. As a workaround, try the below command.

      Get-Content .\Computers.txt | .\Get-InstalledSoftware.ps1 | foreach {
      .\Uninstall-InstalledSoftware.ps1 -ComputerName $_.ComputerName -AppGUID $_.AppGUID
      }

      Please test it in lab toughly before trying on production.

  • mc July 31, 2012, 5:24 pm

    I just found this yesterday. I was wondering if anyone has modified with “if” statements for OS. Win 7 apps are located here:
    “software\wow6432node\microsoft\Windows\currentversion\uninstall”. I was going to play with it this week to try and get it to work for both XP and win 7. But if anyone already has could you post it?

    Thanks for all the great work!

  • Jonny May 29, 2013, 7:26 pm

    Hi Sitaram,

    thanks for the script, its working good, but it will only uninstall from a single server when i try to use get-computers.txt.

    If i run this:

    Get-Content c:\temp\Computers.txt | .\Get-InstalledSoftware.ps1 | Where {$_.AppName -match “iTunes” } | .\Uninstall-InstalledSoftware.ps1

    without the ‘uninstall’ on the end ..then it shows me the software installed on all machines, but when I add the ‘uninstall’ back in ..it only removes the software from a single server?

    Do you know what the problem could be?

    cheers,
    Jon

  • Jonny May 29, 2013, 7:26 pm

    Ignore, just read above!

  • E5E5 March 2, 2014, 7:09 pm

    Hello,
    This is very useful thank you so much!.
    I’m trying to install an update to a remote machine with modifying your uninstall script like this…
    $product = [WMICLASS]”\\$computerName\ROOT\CIMV2:win32_Product”
    $returnval = $product.Install(“msiexec.exe `/update AnUpdate.msp `/qn”)
    Although I am member of the Administrators group of the remote machine ; it gives me “You don’t have sufficient permissions to trigger the command “. Do you have any idea to solve it?
    Thanks

  • Liew May 8, 2014, 8:47 am

    I Trying below method but when I key in incorrect App GUID, the return value is still 0…. Do you know why?

    try {
    $returnval = ([WMICLASS]”\\$computerName\ROOT\CIMV2:win32_process”).Create(“msiexec `/x$AppGUID `/norestart `/qn”)
    } catch {
    write-error “Failed to trigger the uninstallation. Review the error message”
    $_
    exit
    }
    switch ($($returnval.returnvalue)){
    0 { “Uninstallation command triggered successfully, please wait for the software uninstallation” }
    2 { “Access is denied on $Computer” }
    3 { “You don’t have sufficient permissions to trigger the command on $Computer” }
    8 { “An unknown error has occurred” }
    9 { “Path Not Found” }
    9 { “Invalid Parameter”}
    }

    • Sitaram Pamarthi May 12, 2014, 9:19 pm

      The Create method of Win32_Process class worries about whether process is created or not but doesn’t care what its return code.The return value indicate whether command triggered or not only. You need to take different approach if you want to start a process and analyze the return code.

      • s31064 June 8, 2017, 9:51 pm

        Would changing
        $returnval = ([WMICLASS]”\\$computerName\ROOT\CIMV2:win32_process”).Create(“msiexec `/x$AppGUID `/norestart `/qn”)

        to

        $arguments = @(
        ‘/x’
        “$AppGUID”
        ‘/qn’
        ‘/norestart’)
        $returnval = Start-Process -FilePath msiexec.exe -ArgumentList $arguments -Wait -PassThru -Verb runas -Verbose
        $returnval.ExitCode

        give you what Liew is looking for?

  • Ram July 16, 2014, 9:39 am

    Hi Sitaram,

    Thanks for your script, I am trying to uninstall packages on remote servers using below script. This works on my local machine, can you please help me on how to run this script remotely.

    Uninstall-Program(“Displayname”)
    Function Uninstall-Program([string]$name)
    {
    $success = $false

    # Read installation information from the registry
    $registryLocation = Get-ChildItem “HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\”
    foreach ($registryItem in $registryLocation)
    {
    # If we get a match on the application name
    if ((Get-itemproperty $registryItem.PSPath).DisplayName -eq $name)
    {
    # Get the product code if possible
    $productCode = (Get-itemproperty $registryItem.PSPath).ProductCode

    # If a product code is available, uninstall using it
    if ([string]::IsNullOrEmpty($productCode) -eq $false)
    {
    Write-Host “Uninstalling $name, ProductCode:$code”

    $args=”/uninstall $code”

    [diagnostics.process]::start(“msiexec”, $args).WaitForExit()

    $success = $true
    }
    # If there is no product code, try to read the uninstall string
    else
    {
    $uninstallString = (Get-itemproperty $registryItem.PSPath).UninstallString

    if ([string]::IsNullOrEmpty($uninstallString) -eq $false)
    {
    # Grab the product key and create an argument string
    $match = [RegEx]::Match($uninstallString, “{.*?}”)
    $args = “/x $($match.Value) /qb”

    [diagnostics.process]::start(“msiexec”, $args).WaitForExit()

    $success = $true
    }
    else { throw “Unable to uninstall $name” }
    }
    }
    }

    if ($success -eq $false)
    { throw “Unable to find application $name” }
    }

    • Sitaram Pamarthi July 16, 2014, 2:56 pm

      Why don’t you use the approach that I mentioned in my post. The big problem with your code is, it is accessing the registry using Get-ChildItem cmdlet which can not be used for querying remote registry. The approach I mentioned in the post works well.

  • sethupathiraja September 22, 2014, 1:43 pm

    realy it worth . kindly send me if we have to do it for multiple computers

  • Tom November 21, 2014, 2:07 am

    Hi, I work at a school that uses Windows Server 2008 to manage desktops and laptops. Will this script work for uninstalling msi packages that have missing msi file? For example, the old google chrome is installed on a client and I deleted the msi installation file for that version. I try to manually uninstall chrome, it says that the msi cannot be found, so I cannot remove it. I would have to run ccleaner or revo uninstaller to remove all trace of google chrome before the group policy can install the latest chrome msi.

  • Marc February 28, 2015, 4:39 am

    Great work on this script!

    I’m trying to uninstall PowerChute Network Shutdown (Not an MSI) from the reg key.

    Using this command:
    get-content C:\Results.csv | .\get-installedSoftware.ps1 | ?{$_.appname -eq “Powerchute Network Shutdown”} |.\unistall-installedsoftware.ps1

    Problem is that some servers have the uninstall key in
    C:\Program Files\APC\PowerChute\uninstall.exe OR
    D:\Program Files\APC\PowerChute\uninstall.exe

    Do you have any idea on how to modify the uninstall-installedSoftware to pick this up?

    Thanks
    Marc

  • Gajendra March 20, 2015, 7:23 pm

    I have to uninstall multiple software one by one from multiple computers,how can i achieve this with Uninstall-InstalledSoftware.ps1

  • sherman June 24, 2015, 8:51 pm

    What if the uninstall requires a username and password? Symantec Endpoint Encryption starts the uninstall, then pops up a supply a username and password box.

    thanks so much.
    jason

  • Jack November 9, 2016, 4:22 am

    Hi,

    I tried to Uninstall some software on multiple computers at company. I testing on my virtual environment first. On my CLIENT1, I installed “Java 8 Update 111” and runnning Get-InstalledSoftware.ps1 and out put is:

    ComputerName: CLIENT1
    AppName: Java 8 Update 111
    UninstallKey: MsiExec.exe /X{26A24AE4-039D-4CA4-87B4-2F32180111F0}
    AppGUID : {26A24AE4-039D-4CA4-87B4-2F32180111F0}

    When I run the script: .\Get-InstalledSoftware.ps1 -ComputerName CLIENT1 |? {$_.AppName -eq “Java 8 Update 111” } | .\Uninstall-InstalledSoftware.ps1. I get that message “This action is only valid for products that are currently installed”. It’s seem like the script doesn’t looking for the software that installed on my CLIENT1 machine. Any help?

    • Wintel Rocks December 15, 2016, 8:30 pm

      Hi,

      Do you see it working if you supply AppGUID directly to .\Uninstall-InstalledSoftware.ps1 script?

  • Convertible June 2, 2017, 7:19 pm

    Very nice article. I definitely appreciate this website.
    Keep it up!

  • chandan December 6, 2017, 12:20 pm

    Hi Techibee..,,i have been reading your solutions using PS but since im a beginner in PS so your help will save my recent task…
    i need to execute a process on a remote computer which im able to do but that process is going at the background of the remote computer which im able to see from task manager >proccesses
    please help me which command i can use to bring the process at the windows interface .
    im using below command to execute the same

    $Servers = Get-Content “c:\Users\abc\Desktop\copyservers.txt”
    Foreach ($server in $Servers) {
    $command =”C:\users\chandan\abcTool.exe -Shortcut.lnk” ( This shortcut link file have admin rights and this shortcut link with admin rights is available at every server mentioned in source file)
    $cmd = “CMD.EXE /c “+$command
    Invoke-WmiMethod -class Win32_process -name Create -ArgumentList $cmd -ComputerName $server
    }

    your help in this regard will be highly appreciated

    thanks
    chandan

  • Vinu January 9, 2020, 12:49 pm

    Its really an amazing work!
    Much appreciated if you add some code to export the result example ,
    computer name,Application uninstalled and status eg Success, error etc..
    This output file will be really help in case of multiple machines trigger

  • hemant February 20, 2020, 11:51 am

    Hi,
    I’m new to PowerShell scripting and I need to be able to use this script to uninstall one app on our remote systems through Group policy. I have checked and tested the uninstall script to remove the app from local system but it is showing the below:

    cmdlet Uninstall-InstalledSoftwareForEXE.ps1 at command pipeline position 1
    Supply values for the following parameters:
    appguid:

    I have the APPGUID which i got from your installed software script.
    Kindly help to enter the APPGUID value in uninstall script itself so that i can run it through AD. Also, can I distribute this in a .bat file?
    Rgds,
    Hemant

    • Wintel Rocks February 29, 2020, 4:57 pm

      You can try this.
      Uninstall-InstalledSoftware.ps1 -AppGUID

  • Jonathan Ocampo March 18, 2021, 2:29 pm

    Hi i cant remove this item using this method, please advice. thanks a lot in advance.

    ComputerName : localhost
    AppName : Skype for Business Basic 2016 – en-us
    AppVersion : 16.0.13127.21348
    AppVendor : Microsoft Corporation
    InstalledDate :
    UninstallKey : “C:\Program Files\Common Files\Microsoft Shared\ClickToRun\OfficeClickToRun.exe” scenario=install scenariosubtype=ARP sourcetype=None productstoremove=SkypeforBusinessEntryRetail.16_en-us_x-none culture=en-us
    version.16=16.0
    AppGUID : SkypeforBusinessEntryRetail – en-us
    SoftwareArchitecture : x64
    PSComputerName : localhost
    RunspaceId : 7c664cf2-18ee-4ffc-9198-f40fdefc2e31