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:
- Run Get-InstalledSoftware.ps1 script and note the GUID of application that you want to uninstall.
- 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.
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?
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.
Hi
Uninstall doesn`t work on window 2003/2008 server. It do says uninstalation triggred but doesn`t uninstall the software
ND
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.
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
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…
I tried this option but it too didn’t work. it gives and error [Path not found, Invalid Parameter]
sounds like the app has some issues with uninstallation. Have you tried doing it manually from Add/Remove Programs and is working fine?
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
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.
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!
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..
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”
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!
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.
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!
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.
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!
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
Ignore, just read above!
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
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”}
}
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.
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?
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” }
}
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.
realy it worth . kindly send me if we have to do it for multiple computers
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.
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
I have to uninstall multiple software one by one from multiple computers,how can i achieve this with Uninstall-InstalledSoftware.ps1
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
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?
Hi,
Do you see it working if you supply AppGUID directly to .\Uninstall-InstalledSoftware.ps1 script?
Very nice article. I definitely appreciate this website.
Keep it up!
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
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
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
You can try this.
Uninstall-InstalledSoftware.ps1 -AppGUID
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