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

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

15 ответов

Решение
$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'"

РЕДАКТИРОВАТЬ: За эти годы этот ответ получил довольно много голосов. Я хотел бы добавить несколько комментариев. С тех пор я не использовал 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}

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

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

Или же

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

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

get-package *notepad* |% { & $_.Meta.Attributes["UninstallString"]}
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"

Чтобы добавить немного к этому посту, мне нужно было иметь возможность удалять программное обеспечение с нескольких серверов. Я использовал ответ Джеффа, чтобы привести меня к этому:

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

Я обнаружил, что класс 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, использующий 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"

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

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

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

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

Основываясь на ответе Джеффа Хиллмана:

Вот функция, которую вы можете просто добавить в свой 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 может занять некоторое время, так что наберитесь терпения!

С помощью Windows PowerShell 5.1 вы можете вызвать:Uninstall-Package -Name <appname>. См. https://learn.microsoft.com/en-us/powershell/module/packagemanagement/uninstall-package?view=powershellget-2.x .

Для Windows 11 и Windows 10 вы можете использоватьwingetинструмент в PowerShell для управления приложениями, поэтому для удаления приложения вызовите:winget uninstall <appname>. Подробнее см. https://learn.microsoft.com/en-us/windows/package-manager/winget/ .

Использование:

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.

В более поздних системах Windows вы можете использовать следующее для удаления установленного программного обеспечения msi. Вы также можете проверить $pkg.ProviderName -EQ "msi", если хотите.

      $pkg = get-package *name*
$prodCode = "{" + $pkg.TagId + "}"
msiexec.exe /X $prodCode /passive

Для большинства моих программ скрипты в этом посте сделали свою работу. Но мне пришлось столкнуться с устаревшей программой, которую я не мог удалить, используя 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 может работать

Для установки msi отлично работает «удалить-пакет что угодно». Для установок, отличных от msi (поставщик программ), требуется больше синтаксического анализа строк. Это также должно учитывать, если exe-файл удаления находится в пути с пробелами и заключен в двойные кавычки. Install-package работает и с 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 }
Другие вопросы по тегам