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

有没有一种简单的方法可以使用 PowerShell 连接到标准的“ 添加或删除程序”功能?或者检查应用程序是否已安装?

386123 次浏览
$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'"

为了修复 Jeff Hillman 文章中的第二个方法,你可以这样做:

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

或者

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

为了给这篇文章增加一点内容,我需要能够从多个服务器上删除软件。我用杰夫的回答找到了这个:

首先我得到了一个服务器列表,我使用了一个 广告查询,但是你可以随意提供计算机名称的数组:

$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 属性来匹配而不是名称,只是为了确保卸载的是正确的应用程序。

我会做出我自己的一点贡献。我需要从同一台计算机上删除包的列表。这是我想出来的剧本。

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

我希望这个能派上用场。

请注意,我欠大卫 Stetler 这个脚本的功劳,因为它是基于他的。

用途:

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文件,如图所示。让它从 广告检索所有系统,并尝试在所有系统上卸载多个应用程序。

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

未经测试:

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

它所没有的:

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

我无法使用 uninstall ()。尝试,我得到一个错误告诉我,调用一个表达式的值为 NULL 的方法是不可能的。相反,我使用了 RemoveWmiObject,它似乎实现了同样的功能。

注意 : 如果没有给定计算机名,它将从 ActiveDirectory 中的 全部系统中删除软件。

我发现不推荐使用 Win32 _ Product 类,因为它会触发修复,而且没有进行查询优化

我发现从 Sitaram Pamarthi 的 这篇文章与脚本卸载,如果你知道的应用程序指南。他还提供了另一个脚本来搜索真正快速的 给你应用程序。

像这样使用: . 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"}
}

编辑: 多年来,这个答案得到了不少人的赞同。我想补充一些意见。从那以后,我再也没有使用过 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}

基于 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 + "'")
}
}

假设您想卸载 记事本 + + ,只需在 PowerShell 中键入以下内容:

> uninstall("notepad++")

只是要知道,Get-WmiObject可能需要一些时间,所以要有耐心!

对于我的大多数程序来说,这篇文章中的脚本起到了作用。 但是我不得不面对一个遗留的程序,我无法使用 msiExec.exe 或 Win32 _ Product 类删除它。(由于某种原因,我得到了出口0,但程序仍然存在)

我的解决方案是使用 Win32 _ Process 类:

谢谢的帮助下,这个命令用于获取卸载 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是成功的

上述命令也可以远程运行-我使用调用命令,但我相信添加参数-计算机名可以工作

下面是使用 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"
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"

一行代码:

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

对于 msi 安装,“ uninstall-package whatever”可以正常工作。对于非 msi 安装(程序提供程序) ,需要进行更多的字符串解析。这还应该考虑卸载 exe 是否位于带空格的路径中并且带有双引号。安装包也可以与 msi 一起工作。

$uninstall = get-package whatever | % { $_.metadata['uninstallstring'] }
# split quoted and unquoted things on whitespace
$prog, $myargs = $uninstall | select-string '("[^"]*"|\S)+' -AllMatches |
% matches | % value
$prog = $prog -replace '"',$null  # call & operator doesn't like quotes
$silentoption = '/S'
$myargs += $silentoption  # add whatever silent uninstall option
& $prog $myargs  # run uninstaller silently

如果你需要等待的话,Start-process 不介意双引号:

# "C:\Program Files (x86)\myapp\unins000.exe"
get-package myapp | foreach { start -wait $_.metadata['uninstallstring'] /SILENT }