Powershell: удаление приложения с помощью UpgradeCode
Когда я обновляю / понижаю версию своего приложения с помощью скрипта Powershell, я хочу сначала принудительно удалить установленную версию перед запуском нового установщика.
Как я могу сделать это с Powershell, используя UpgradeCode приложения?
Делать это по имени приложения было бы менее надежным.
3 ответа
Поскольку вы упоминаете код обновления, это должно означать, что вы говорите о файле MSI ( установщик Windows). Как утверждают другие, такая деинсталляция обычно выполняется автоматически с помощью правильно созданного пакета MSI - это называется серьезным обновлением - которое, по сути, является деинсталляцией существующей версии продукта, а затем установкой самой новой версии.
В таблице обновлений устанавливаемого MSI будет указано, какие существующие пакеты на коробке будут удалены перед установкой новой версии. Теоретически вы можете удалить любое количество существующих установок. Вы даже можете удалить конкурентный продукт, если вы без ума от шляпника. Честно говоря, и удивительно, я никогда не пытался удалить несколько продуктов во время одного крупного обновления - это редко требуется. В большинстве случаев вы удаляете один существующий продукт, а затем устанавливаете последнюю версию.
Вы можете изменить таблицу обновлений, используя преобразование, чтобы изменить поведение основного обновления - другими словами, запустить или прекратить удаление определенной ранее существующей установки.
Вы также можете перечислить все связанные продукты, которые используют один и тот же код обновления, вызвав эту функцию MSI API (COM - VBScript, используемый в качестве примера):
Set installer = CreateObject("WindowsInstaller.Installer")
' Enumerate all products related to "Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148"
' {AA783A14-A7A3-3D33-95F0-9A351D530011} is the upgrade code
Set upgrades = installer.RelatedProducts("{AA783A14-A7A3-3D33-95F0-9A351D530011}")
For Each u In upgrades
MsgBox u, vbOKOnly, "Product Code: "
Next
Затем вы можете удалить продукты, передав код (ы) продукта в командную строку msiexec.exe (см. Ниже, как это сделать с помощью автоматизации COMI MSI API):
msiexec.exe /x {11111111-1111-1111-1111-11111111111X} /L*V "C:\msilog.log" REBOOT=ReallySuppress
Краткое объяснение параметров (так как я рекомендую эту опцию):
/X = run uninstall sequence
/QN = run completely silently
/L*V "C:\msilog.log"= verbose logging at path specified
{11111111-1111-1111-1111-11111111111X} = product guid of app to uninstall
REBOOT=ReallySuppress = prevent reboot without warning (badly authored MSI packages)
Если вы не хотите удалять через msiexec.exe
Затем вы можете найти множество способов вызвать MSI-деинсталляцию здесь: Деинсталляция MSI-файла из командной строки без использования msiexec.
И вы можете найти код продукта установленного MSI несколькими различными способами: Как я могу найти GUID продукта установленной установки MSI?
ОБНОВЛЕНИЕ: я думаю, я забыл очевидное, вы можете удалить непосредственно с помощью автоматизации MSI API. В приведенном ниже сценарии мы получаем все продукты, использующие один и тот же код обновления, а затем удаляем их последовательно.
Обратите внимание, что при запуске в режиме без вывода сообщений вы должны работать с правами администратора, поскольку UAC может быть подавлен, а затем удаление обычно завершится неудачно (разрешение отклонено). Из-за этого нижеприведенный скрипт выполняет деинсталляцию в интерактивном режиме, что позволяет запрашивать и повышение прав UAC
И если это не очевидно: запуск этого скрипта приведет к удалению Orca! Я использую этот продукт в качестве образца, потому что он быстро устанавливается снова ( подсказки по быстрому поиску установщика, если вам нужно перейти к нижней части здесь - найдите "orca"):
БОЛЬШОЙ ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ:
Метод COM installer.ConfigureProduct
не принимает никаких аргументов, которые позволяют нам передавать в REBOOT=ReallySuppress
, Это означает, что (очень) плохо созданный пакет, который запускает действие ScheduleReboot (или использует более неясное волшебство, чтобы вызвать перезагрузку) - может перезагрузить систему без предупреждения, если вы запустите приведенный ниже скрипт с правами администратора и в режиме без вывода сообщений.
Есть более новый звонок ConfigureProductEx
которая доступна как функция Win32, но не предоставляется через интерфейс автоматизации COM. если ты platform invoke
Вы можете использовать этот вызов - здесь есть пример C++ в разделе 14: Удаление MSI-файла из командной строки без использования msiexec. Или вы можете использовать функцию DTF из набора инструментов WiX (см. Раздел 6 в той же ссылке, что и в примере C++).
ОБНОВЛЕНИЕ июль 2018 года:
Set installer = CreateObject("WindowsInstaller.Installer")
installer.InstallProduct "product.msi", "REMOVE=ALL REBOOT=ReallySuppress"
Set installer = Nothing
Возможно, приведенный выше фрагмент является лучшим способом удаления? Это должно подавлять любые перезагрузки. У меня нет времени или настройки для его тестирования прямо сейчас (на коробке с Linux), но я хотел добавить его, прежде чем забыл.
Оригинальный скрипт удаления:
Const msiUILevelNone = 2
Const msiInstallStateAbsent = 2
Set installer = CreateObject("WindowsInstaller.Installer")
'installer.UILevel = msiUILevelNone ' Disabled to prevent silent uninstall. Now the UAC prompt will show
' Uninstall Orca, replace upgrade code with yours
Set products = installer.RelatedProducts("{CFF4D510-79B2-1CCD-0061-5741A0565A76}")
For Each product In products
' MsgBox "Product Code: " & product ' Show the product code found, if you want
' The following call when run silently with admin rights may reboot the system without warning!
' This is due to badly authored MSI packages - most packages will not trigger this problem.
installer.ConfigureProduct product, 0, msiInstallStateAbsent ' Uninstall product
' See text above for info on the newer ConfigureProductEx method.
Next
Set installer = Nothing
MsgBox "Finished" ' Just so we know the script ran if nothing found to uninstall
Некоторые ссылки:
- Есть ли альтернатива GUID при использовании msiexec для удаления приложения? (удалить по названию продукта)
- Как я могу удалить приложение с помощью PowerShell?
- Как я могу использовать powershell для запуска через установщик?
- WIX (удалить все предыдущие версии)
- Обновление Wix переходит в режим обслуживания и никогда не обновляется (различные способы удаления, по коду продукта, по коду обновления и т. Д.)
Поскольку в вопросе конкретно упоминается powershell, я просто поставлю это здесь. Существуют и другие решения PS, связанные с использованием WMI и/или Get-Package. Это решение основано на https://outnull.wordpress.com/2016/11/02/uninstalling-application-based-on-upgradecode/ , но принимает различные формы синтаксиса кода обновления и пытается избежать манипуляций со строками при преобразовании. в/из пакета/обновления Guid и представления реестра.
$upgradecode = "{CFF4D510-79B2-1CCD-0061-5741A0565A76}"
$installer = Join-Path -Path $env:SystemRoot -ChildPath "system32\msiexec.exe" -Resolve
function Reverse-Nibbles {
param ( [byte[]] $bytes )
# reverse nibbles of each byte
for($i = 0; $i -lt $bytes.Length; $i++ )
{
$bytes[$i] = (($bytes[$i] -band 0x0F0F) -shl 4) -bor (($bytes[$i] -band 0xF0F0) -shr 4)
}
Write-Output -NoEnumerate $bytes
}
function GuidToRegString {
param ( [guid] $guid )
$bigendian = (Reverse-Nibbles $guid.ToByteArray())
return [System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary]::new($bigendian).ToString()
}
function RegStringToGuid {
param ( [string] $guid )
$littleendian = (Reverse-Nibbles ([System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary]::Parse($guid).Value))
return [guid]::new($littleendian)
}
$upcode = GuidToRegString ([guid]::Parse($upgradecode))
if (Test-Path -Path "HKLM:\Software\Classes\Installer\UpgradeCodes\$upcode") {
$products = RegStringToGuid (Get-Item -Path "HKLM:\Software\Classes\Installer\UpgradeCodes\$upcode").Property
foreach ($prod in $products) {
$pguid = [guid]::new($prod)
$p = $pguid.ToString("B")
if ((Test-Path -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\$p") -or
(Test-Path -Path "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$p"))
{
$logfile = Join-Path -Path $PSScriptRoot -ChildPath uninstall-$($pguid.ToString("D")).log
$args = @( "/x", $p, "/l*v", """$logfile""", "/q", "COMPLETE_UNINSTALL=1", "REBOOT=REALLYSUPPRESS" )
Write-Host "Uninstalling $p"
$uninst = Start-Process -FilePath """$installer""" -ArgumentList $args -PassThru -Wait
Write-Host $uninst.ExitCode
}
}
}
ИспользоватьWindowsInstaller.Installer
чтобы найти код продукта в коде обновления, затем запуститеmsiexec /x {productcode}
.
Пример использования PowerShell для удаления кода обновления{939BFD63-B6E1-44BC-BD9E-225DDC30CF51}
:
PS C:\Users\user> $inst = New-Object -ComObject "WindowsInstaller.Installer"
PS C:\Users\user> $inst.RelatedProducts('{939BFD63-B6E1-44BC-BD9E-225DDC30CF51}')
{F587B97A-43C7-43D9-9243-DF76B0A54DE8}
PS C:\Users\user> msiexec /x "{F587B97A-43C7-43D9-9243-DF76B0A54DE8}"
PS C:\Users\user>