【发布时间】:2010-09-11 22:17:52
【问题描述】:
是否有一种简单的方法可以使用 PowerShell 连接到标准的“添加或删除程序”功能以卸载现有应用程序?或者检查应用程序是否已安装?
【问题讨论】:
标签: windows powershell windows-installer uninstallation
是否有一种简单的方法可以使用 PowerShell 连接到标准的“添加或删除程序”功能以卸载现有应用程序?或者检查应用程序是否已安装?
【问题讨论】:
标签: windows powershell windows-installer uninstallation
$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'"
【讨论】:
(gwmi Win32_Product | ? Name -eq "Software").uninstall() 一点代码高尔夫。
要修复 Jeff Hillman 帖子中的第二种方法,您可以这样做:
$app = Get-WmiObject
-Query "SELECT * FROM Win32_Product WHERE Name = 'Software Name'"
或者
$app = Get-WmiObject -Class Win32_Product `
-Filter "Name = 'Software Name'"
【讨论】:
为了在这篇文章中添加一点内容,我需要能够从多个服务器中删除软件。我用杰夫的回答引导我这样做:
首先我得到了一个服务器列表,我使用了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()
}
我使用 IdentificationNumber 属性而不是名称进行匹配,以确保我卸载了正确的应用程序。
【讨论】:
我会做出自己的一点贡献。我需要从同一台计算机上删除一个包列表。这是我想出的脚本。
$packages = @("package1", "package2", "package3")
foreach($package in $packages){
$app = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -match "$package"
}
$app.Uninstall()
}
我希望这被证明是有用的。
请注意,我欠 David 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 文件。让它从AD 中检索所有系统并尝试卸载所有系统上的多个应用程序。
我使用 IdentificationNumber 来搜索 David Stetler 输入的软件原因。
未测试:
它没有什么:
我无法使用uninstall()。尝试我得到一个错误,告诉我为具有 NULL 值的表达式调用方法是不可能的。相反,我使用了 Remove-WmiObject,它似乎完成了相同的操作。
注意:如果没有给出计算机名称,则会从 Active Directory 中的所有系统中删除该软件。
【讨论】:
我发现不推荐使用 Win32_Product 类,因为它会触发修复并且未对查询进行优化。 Source
我从 Sitaram Pamarthi 找到了 this post,如果您知道应用程序 guid,则可以使用脚本进行卸载。他还提供了另一个脚本来非常快速地搜索应用程序here。
像这样使用:.\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"}
}
【讨论】:
编辑:多年来,这个答案得到了相当多的支持。我想添加一些cmets。从那以后我就没有使用过 PowerShell,但我记得观察到一些问题:
-First 1,但我不确定。随意编辑。使用 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}
【讨论】:
-like "appNam*" 一起使用,因为版本在名称中并且它会更改,但它似乎没有找到该程序。有什么想法吗?
根据 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 可能需要一些时间,所以请耐心等待!
【讨论】:
对于我的大多数程序,这篇文章中的脚本都可以完成这项工作。 但是我不得不面对一个无法使用 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代表成功
上面的命令也可以远程运行——我是使用调用命令完成的,但我相信添加参数 -computername 可以工作
【讨论】:
这是使用 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"]}
【讨论】: