Как я могу удалить приложение с помощью PowerShell?

136

Существует ли простой способ подключиться к стандартной функции « Установка и удаление программ » с помощью PowerShell для удаления существующего приложения ? Или проверить, установлено ли приложение?

Роб Патерсон
источник

Ответы:

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

$app.Uninstall()

Редактировать: Роб нашел другой способ сделать это с параметром Filter:

$app = Get-WmiObject -Class Win32_Product `
                     -Filter "Name = 'Software Name'"
Джефф Хиллман
источник
1
Это довольно много, я бы сказал, что может быть лучше использовать IdentifyingNumber, а не имя, на всякий случай.
Ванны
6
После небольшого исследования вы также можете использовать выражение -filter в Get-WmiObject: $ app = Get-WmiObject -Class Win32_Product -filter "select * from Win32_Product WHERE name = 'Software Name'"
Роб Патерсон,
8
Обратите внимание, что просмотр WMI будет работать только для продуктов, которые были установлены через MSI.
EBGreen
7
Этот класс WMI требует FOREVER для перечисления. Я предлагаю Джеффу, чтобы вы обновили свой код, чтобы включить совет Роба.
halr9000
4
(gwmi Win32_Product | ? Name -eq "Software").uninstall() Немного кода гольф.
круглый
51

РЕДАКТИРОВАТЬ: За эти годы этот ответ получил довольно много голосов. Я хотел бы добавить несколько комментариев. С тех пор я не использовал PowerShell, но помню, что наблюдал некоторые проблемы:

  1. Если для приведенного ниже сценария больше совпадений, чем 1, он не работает, и вы должны добавить фильтр PowerShell, ограничивающий результаты до 1. Я считаю, что это так, -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}
nickdnk
источник
1
Спасибо за это! Я пытаюсь использовать это с, -like "appNam*"так как версия в названии, и она меняется, но, похоже, не находит программу. Любые идеи?
NSouth
1
Найдите функцию -like для powershell, выясните, какой фильтр использовать, как правильно настроить соответствие вашей строке. Просто используйте оболочку для тестирования, и как только вы все сделаете правильно, замените -match :)
nickdnk
2
Это золото. Лично я удаляю «b» из «/ qb», чтобы вам не приходилось видеть никаких диалогов.
WhiteHotLoveTiger
Гораздо быстрее :-)
Оскар Фоли
3
Я превратил это в скрипт .ps1 с подсказкой и информацией «что я собираюсь удалить». gist.github.com/chrisfcarroll/e38b9ffcc52fa9d4eb9ab73b13915f5a
Крис Ф. Кэрролл,
34

Чтобы исправить второй метод в посте Джеффа Хиллмана, вы можете сделать:

$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, поэтому у него не было метода "удаления".
Дуг Дж. Хурас,
7

Я обнаружил, что класс 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"}
 }
Рикардо
источник
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 для сопоставления вместо имени, просто чтобы убедиться, что удаляю правильное приложение.

Дэвид Стетлер
источник
Просто мило это решение
Raffaeu
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"
Эхсан Иран-Неджад
источник
6

Одна строка кода:

get-package *notepad* |% { & $_.Meta.Attributes["UninstallString"]}
Франческо Мантовани
источник
3

Я сделаю свой маленький вклад. Мне нужно было удалить список пакетов с того же компьютера. Это сценарий, который я придумал.

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

Я надеюсь, что это окажется полезным.

Обратите внимание, что я обязан Дэвиду Стетлеру за этот скрипт, поскольку он основан на его.

Бен Ки
источник
2

Вот скрипт PowerShell, использующий msiexec:

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"
RBT
источник
Я совместил этот подход со следующими флагами , по некоторым причинам он работает лучше, чем другие подходы для меня.
Дэвид Роджерс
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 для поиска причины программного обеспечения ввода Дэвида Стетлерса.

Не проверено:

  1. Не добавлять идентификаторы к вызову функции в скрипте, вместо этого запускать скрипт с идентификаторами параметров
  2. Вызов сценария с более чем одним именем компьютера, который автоматически не извлекается из функции
  3. Получение данных из канала
  4. Использование IP-адресов для подключения к системе

Что это не так:

  1. Это не дает никакой информации, если программное обеспечение действительно было найдено в любой данной системе.
  2. Это не дает никакой информации о неудаче или успехе деинсталляции.

Я не смог использовать uninstall (). При попытке получить ошибку, сообщающую, что вызов метода для выражения со значением NULL невозможен. Вместо этого я использовал Remove-WmiObject, который, кажется, делает то же самое.

ПРЕДУПРЕЖДЕНИЕ . Без указания имени компьютера оно удаляет программное обеспечение из ВСЕХ систем в Active Directory.

user3410872
источник
0

Для большинства моих программ скрипты в этом посте сделали свою работу. Но мне пришлось столкнуться с устаревшей программой, которую я не мог удалить, используя msiexec.exe или класс Win32_Product. (по какой-то причине я получил выход 0, но программа все еще была там)

Моим решением было использовать класс Win32_Process:

с помощью nickdnk эта команда должна получить путь к файлу деинсталляции exe:

64bit:

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

32bit:

 [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 может работать

dsaydon
источник