如何使用PowerShell卸载应用程序?

148
有没有一种简单的方法,使用PowerShell钩入标准的“添加或删除程序”功能来卸载现有应用程序?或者检查该应用程序是否已安装?
15个回答

176
$app = Get-WmiObject -Class Win32_Product | Where-Object { 
    $_.Name -match "Software Name" 
}

$app.Uninstall()

编辑:Rob 发现了另一种使用 Filter 参数的方法:

$app = Get-WmiObject -Class Win32_Product `
                     -Filter "Name = 'Software Name'"

1
这就是大部分了,我会说最好使用IdentifyingNumber而不是名称,以防万一。 - Tubs
6
经过一番研究,您也可以使用Get-WmiObject的-filter子句:$app = Get-WmiObject -Class Win32_Product -filter "select * from Win32_Product WHERE name = '软件名称'" - Rob Paterson
9
请注意,查看 WMI 只适用于通过 MSI 安装的产品。 - EBGreen
7
这个 WMI 类的枚举需要非常长的时间。我建议 Jeff 更新代码,采用 Rob 的提示。 - halr9000
6
(gwmi Win32_Product | ? Name -eq "Software").uninstall():一段简短的代码。 - roundar
显示剩余5条评论

60

编辑:这个答案多年来得到了很多赞。我想添加一些评论。 我自那以后就没有使用过PowerShell,但我记得观察到一些问题:

  1. 如果下面的脚本有多个匹配项,则不起作用,必须附加限制结果为1的PowerShell过滤器。 我相信是-First 1,但我不确定。随意编辑。
  2. 如果应用程序未通过MSI安装,则不起作用。之所以编写以下内容,是因为它修改了MSI以无需干预即可卸载,而在使用本地卸载字符串时并不总是默认情况。

使用WMI对象需要很长时间。 如果您只知道要卸载的程序的名称,则非常快。

$uninstall32 = gci "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match "SOFTWARE NAME" } | select UninstallString
$uninstall64 = gci "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match "SOFTWARE NAME" } | select UninstallString

if ($uninstall64) {
$uninstall64 = $uninstall64.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
$uninstall64 = $uninstall64.Trim()
Write "Uninstalling..."
start-process "msiexec.exe" -arg "/X $uninstall64 /qb" -Wait}
if ($uninstall32) {
$uninstall32 = $uninstall32.UninstallString -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
$uninstall32 = $uninstall32.Trim()
Write "Uninstalling..."
start-process "msiexec.exe" -arg "/X $uninstall32 /qb" -Wait}

1
谢谢!我正在尝试使用-like "appNam*",因为版本号在名称中并且会更改,但似乎无法找到该程序。有什么想法吗? - NSouth
1
查找PowerShell中的-like函数,找出要使用哪个过滤器以及如何正确匹配字符串。只需使用shell进行测试,一旦正确匹配,就可以替换-match :) - nickdnk
2
这是黄金。个人而言,我会从“/qb”中删除“b”,这样您就不必看到任何对话框了。 - WhiteHotLoveTiger
4
我把这个变成了一个带有提示和“我即将卸载什么”的信息的.ps1脚本。https://gist.github.com/chrisfcarroll/e38b9ffcc52fa9d4eb9ab73b13915f5a - Chris F Carroll
希望这个能够得到更多的赞。谢谢! - Robson William
显示剩余6条评论

34

为了修复 Jeff Hillman 帖子中的第二种方法,您可以执行以下操作:

$app = Get-WmiObject 
            -Query "SELECT * FROM Win32_Product WHERE Name = 'Software Name'"

或者

$app = Get-WmiObject -Class Win32_Product `
                     -Filter "Name = 'Software Name'"

提醒一下...我发现使用“-Query”而不是“-Filter”选项没有返回WmiObject,因此它没有“卸载(uninstall)”方法。 - Doug J. Huras
1
此解决方案无法通过exe获取安装的程序,只能通过msi获取。因此,它仅适用于通过Microsoft Installer(msi)安装的程序。 - Hüseyin

14

一行代码:

get-package *notepad* |% { & $_.Meta.Attributes["UninstallString"]}

返回 CategoryInfo: InvalidOperation: (:) [], RuntimeException FullyQualifiedErrorId: BadExpression - mgutt
奇怪,这之前是可以工作的。 - Francesco Mantovani

9
function Uninstall-App {
    Write-Output "Uninstalling $($args[0])"
    foreach($obj in Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall") {
        $dname = $obj.GetValue("DisplayName")
        if ($dname -contains $args[0]) {
            $uninstString = $obj.GetValue("UninstallString")
            foreach ($line in $uninstString) {
                $found = $line -match '(\{.+\}).*'
                If ($found) {
                    $appid = $matches[1]
                    Write-Output $appid
                    start-process "msiexec.exe" -arg "/X $appid /qb" -Wait
                }
            }
        }
    }
}

以这种方式调用:

Uninstall-App "Autodesk Revit DB Link 2019"

7
为了补充一下这篇文章,我需要能够从多个服务器上删除软件。我使用了Jeff的答案来引导我到这里:
首先,我得到了一个服务器列表,我使用了AD查询,但你可以按照自己的方式提供计算机名称的数组:
$computers = @("computer1", "computer2", "computer3")

然后我循环遍历它们,将“-computer”参数添加到gwmi查询中:
foreach($server in $computers){
    $app = Get-WmiObject -Class Win32_Product -computer $server | Where-Object {
        $_.IdentifyingNumber -match "5A5F312145AE-0252130-432C34-9D89-1"
    }
    $app.Uninstall()
}

我使用IdentifyingNumber属性进行匹配,而不是名称,只是为了确保我正在卸载正确的应用程序。


这个解决方案真是太棒了。 - Raffaeu

7
我发现Win32_Product类不被推荐使用,因为它会触发修复并且没有进行查询优化。这里是来源
我找到了Sitaram Pamarthi的这篇文章,其中提供了一个脚本来卸载应用程序GUID。他还提供了另一个快速搜索应用程序的脚本,在这里
请按照以下方式使用:.\uninstall.ps1 -GUID {C9E7751E-88ED-36CF-B610-71A1D262E906}
[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"}
 }

4

以下是使用msiexec的PowerShell脚本:

echo "Getting product code"
$ProductCode = Get-WmiObject win32_product -Filter "Name='Name of my Software in Add Remove Program Window'" | Select-Object -Expand IdentifyingNumber
echo "removing Product"
# Out-Null argument is just for keeping the power shell command window waiting for msiexec command to finish else it moves to execute the next echo command
& msiexec /x $ProductCode | Out-Null
echo "uninstallation finished"

1
我将这种方法与以下标志相结合,由于某种原因,这对我来说比其他方法更有效。 - David Rogers

3

我会做出自己的微小贡献。我需要从同一台计算机中删除一系列软件包。这是我想出来的脚本。

$packages = @("package1", "package2", "package3")
foreach($package in $packages){
  $app = Get-WmiObject -Class Win32_Product | Where-Object {
    $_.Name -match "$package"
  }
  $app.Uninstall()
}

我希望这对你有所帮助。

请注意,由于这个脚本是基于David Stetler的脚本开发的,所以他应该得到相应的荣誉。


2

基于Jeff Hillman的回答:

这里有一个函数,您可以将其添加到您的profile.ps1中或在当前PowerShell会话中定义:

# Uninstall a Windows program
function uninstall($programName)
{
    $app = Get-WmiObject -Class Win32_Product -Filter ("Name = '" + $programName + "'")
    if($app -ne $null)
    {
        $app.Uninstall()
    }
    else {
        echo ("Could not find program '" + $programName + "'")
    }
}

假设您想卸载Notepad++。只需在PowerShell中键入以下内容:

> uninstall("notepad++")

请注意,Get-WmiObject可能需要一些时间,请耐心等待!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接