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


Answers:


160
$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而不是名称。
浴缸

6
经过一些研究,您还可以使用Get-WmiObject的-filter子句:$ app = Get-WmiObject -Class Win32_Product -filter“ select * from Win32_Product WHERE name ='Software Name'”
Rob Paterson

8
请注意,查看WMI仅适用于通过MSI安装的产品。
EBGreen

7
此类WMI类需要FOREVER进行枚举。我建议Jeff更新您的代码以包含Rob的技巧。
halr9000

4
(gwmi Win32_Product | ? Name -eq "Software").uninstall() 一点代码高尔夫。
圆形的

51

编辑:多年来,这个答案已经获得了很多好评。我想补充一些意见。从那以后我就没有使用过PowerShell,但是我记得观察到一些问题:

  1. 如果以下脚本的匹配项大于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函数,找出使用哪个过滤器以使其正确匹配您的字符串。只需使用外壳进行测试,然后正确使用-match :)
nickdnk

2
这是黄金。就个人而言,我从“ / qb”中删除了“ b”,因此您无需查看任何对话框。
WhiteHotLoveTiger

快得多了:-)
奥斯卡·佛利

3
我将其转换为带有提示和“我将要卸载的内容”信息的.ps1脚本。gist.github.com/chrisfcarroll/e38b9ffcc52fa9d4eb9ab73b13915f5a
Chris F Carroll

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

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"}
 }

7

为了给这篇文章增加一点,我需要能够从多个服务器上删除软件。我用杰夫的答案来引导我:

首先,我获得了服务器列表,使用了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属性而不是名称进行匹配,以确保我正在卸载正确的应用程序。


简单可爱的解决方案
Raffaeu14年

6
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"


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

这是使用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

基于杰夫·希尔曼的答案:

这是您可以添加到您的函数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可能需要一些时间,请耐心等待!


0

用:

function remove-HSsoftware{
[cmdletbinding()]
param(
[parameter(Mandatory=$true,
ValuefromPipeline = $true,
HelpMessage="IdentifyingNumber can be retrieved with `"get-wmiobject -class win32_product`"")]
[ValidatePattern('{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}}')]
[string[]]$ids,
[parameter(Mandatory=$false,
            ValuefromPipeline=$true,
            ValueFromPipelineByPropertyName=$true,
            HelpMessage="Computer name or IP adress to query via WMI")]
[Alias('hostname,CN,computername')]
[string[]]$computers
)
begin {}
process{
    if($computers -eq $null){
    $computers = Get-ADComputer -Filter * | Select dnshostname |%{$_.dnshostname}
    }
    foreach($computer in $computers){
        foreach($id in $ids){
            write-host "Trying to uninstall sofware with ID ", "$id", "from computer ", "$computer"
            $app = Get-WmiObject -class Win32_Product -Computername "$computer" -Filter "IdentifyingNumber = '$id'"
            $app | Remove-WmiObject

        }
    }
}
end{}}
 remove-hssoftware -ids "{8C299CF3-E529-414E-AKD8-68C23BA4CBE8}","{5A9C53A5-FF48-497D-AB86-1F6418B569B9}","{62092246-CFA2-4452-BEDB-62AC4BCE6C26}"

尚未经过全面测试,但已在PowerShell 4下运行。

我已经运行了PS1文件,如此处所示。让它从AD中检索所有系统,并尝试在所有系统上卸载多个应用程序。

我已经使用IdentifyingNumber搜索David Stetlers输入的软件原因。

未经测试:

  1. 不要在脚本中的函数调用中添加ID,而是使用参数ID启动脚本
  2. 无法从函数中自动检索具有超过1个计算机名的脚本
  3. 从管道中检索数据
  4. 使用IP地址连接到系统

它没有:

  1. 如果在任何给定系统上实际找到该软件,它不会提供任何信息。
  2. 它不提供有关卸载失败或成功的任何信息。

我无法使用uninstall()。尝试收到一个错误消息,告诉我无法为值为NULL的表达式调用方法。取而代之的是,我使用了Remove-WmiObject,它似乎可以达到相同的效果。

注意:如果没有提供计算机名称,它将从Active Directory中的所有系统中删除该软件。


0

对于我的大多数程序,这篇文章中的脚本都可以完成工作。但是我不得不面对一个无法使用msiexec.exe或Win32_Product类删除的旧程序。(由于某种原因,我退出了0,但程序仍然存在)

我的解决方案是使用Win32_Process类:

借助nickdnk的帮助,此命令将获取卸载exe文件的路径:

64位:

[array]$unInstallPathReg= gci "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match $programName } | select UninstallString

32位:

 [array]$unInstallPathReg= gci "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" | foreach { gp $_.PSPath } | ? { $_ -match $programName } | select UninstallString

您将必须清理结果字符串:

$uninstallPath = $unInstallPathReg[0].UninstallString
$uninstallPath = $uninstallPath -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
$uninstallPath = $uninstallPath .Trim()

现在,当您具有相关的程序卸载exe文件路径时,可以使用此命令:

$uninstallResult = (Get-WMIObject -List -Verbose | Where-Object {$_.Name -eq "Win32_Process"}).InvokeMethod("Create","$unInstallPath")

$ uninstallResult-将具有退出代码。0是成功

上面的命令也可以远程运行-我使用invoke命令做到了,但是我相信添加参数-computername可以工作

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.