Jak mogę odinstalować aplikację przy użyciu PowerShell?

136

Czy istnieje prosty sposób na podłączenie się do standardowej funkcji „ Dodaj lub usuń programy ” przy użyciu programu PowerShell w celu odinstalowania istniejącej aplikacji ? Albo sprawdzić, czy aplikacja jest zainstalowana?

Rob Paterson
źródło

Odpowiedzi:

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

$app.Uninstall()

Edycja: Rob znalazł inny sposób na zrobienie tego z parametrem Filter:

$app = Get-WmiObject -Class Win32_Product `
                     -Filter "Name = 'Software Name'"
Jeff Hillman
źródło
1
To prawie wszystko, powiedziałbym, że na wszelki wypadek lepiej byłoby użyć numeru identyfikującego niż nazwy.
Tubs
6
Po krótkiej analizie możesz również użyć klauzuli -filter w Get-WmiObject: $ app = Get-WmiObject -Class Win32_Product -filter "wybierz * z Win32_Product WHERE name = 'Nazwa oprogramowania'"
Rob Paterson
8
Należy pamiętać, że przeglądanie WMI działa tylko w przypadku produktów, które zostały zainstalowane za pośrednictwem MSI.
EBGreen
7
Wyliczenie tej klasy WMI trwa ZAWSZE. Sugeruję Jeffowi, aby zaktualizował swój kod, aby zawierał wskazówkę Roba.
halr9000
4
(gwmi Win32_Product | ? Name -eq "Software").uninstall() Mały golf kodowy.
roundar
51

EDYCJA: Na przestrzeni lat ta odpowiedź zyskała kilka pozytywnych głosów. Chciałbym dodać kilka komentarzy. Od tego czasu nie korzystałem z PowerShell, ale pamiętam, że zauważyłem kilka problemów:

  1. Jeśli jest więcej dopasowań niż 1 dla poniższego skryptu, nie działa i musisz dołączyć filtr PowerShell, który ogranicza wyniki do 1. Wydaje mi się, że tak, -First 1ale nie jestem pewien. Zapraszam do edycji.
  2. Jeśli aplikacja nie jest zainstalowana przez MSI, nie działa. Powodem, dla którego został napisany jak poniżej, jest to, że modyfikuje MSI w celu odinstalowania bez interwencji, co nie zawsze jest przypadkiem domyślnym w przypadku używania natywnego ciągu dezinstalacji.

Korzystanie z obiektu WMI trwa wiecznie. Jest to bardzo szybkie, jeśli znasz tylko nazwę programu, który chcesz odinstalować.

$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
źródło
1
Dzięki za to! Próbuję tego użyć, -like "appNam*"ponieważ wersja jest w nazwie i zmienia się, ale wydaje się, że nie można znaleźć programu. Jakieś pomysły?
NSouth
1
Wyszukaj podobną do funkcji funkcję PowerShell, dowiedz się, którego filtra użyć i jak sprawić, by pasował poprawnie do łańcucha. Po prostu użyj powłoki, aby przetestować, a kiedy już to zrobisz, zamień -match :)
nickdnk
2
To jest złoto. Osobiście usuwam „b” z „/ qb”, więc nie musisz widzieć żadnych okien dialogowych.
WhiteHotLoveTiger
Dużo szybciej :-)
Oscar Foley
3
Przekształciłem to w skrypt .ps1 z podpowiedzią i informacją „Co mam zamiar odinstalować”. gist.github.com/chrisfcarroll/e38b9ffcc52fa9d4eb9ab73b13915f5a
Chris F Carroll
34

Aby naprawić drugą metodę w poście Jeffa Hillmana, możesz wykonać:

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

Lub

$app = Get-WmiObject -Class Win32_Product `
                     -Filter "Name = 'Software Name'"
Robert Wagner
źródło
Tylko uwaga ... Odkryłem, że użycie opcji „-Query” zamiast opcji „-Filter” nie zwróciło obiektu WmiObject, więc nie ma metody „odinstalowania”.
Doug J. Huras
7

Dowiedziałem się, że klasa Win32_Product nie jest zalecana, ponieważ wyzwala naprawy i nie jest zoptymalizowana pod kątem zapytań. Źródło

Znalazłem ten post od Sitaram Pamarthi ze skryptem do odinstalowania, jeśli znasz przewodnik po aplikacji. On również dostarcza inny skrypt do wyszukiwania aplikacji bardzo szybko tutaj .

Użyj w ten sposób:. \ 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"}
 }
Ricardo
źródło
7

Aby trochę dodać do tego postu, potrzebowałem możliwości usuwania oprogramowania z wielu serwerów. Użyłem odpowiedzi Jeffa, aby doprowadzić mnie do tego:

Najpierw otrzymałem listę serwerów, użyłem zapytania AD , ale możesz podać tablicę nazw komputerów, jak chcesz:

$computers = @("computer1", "computer2", "computer3")

Następnie przejrzałem je, dodając parametr -computer do zapytania gwmi:

foreach($server in $computers){
    $app = Get-WmiObject -Class Win32_Product -computer $server | Where-Object {
        $_.IdentifyingNumber -match "5A5F312145AE-0252130-432C34-9D89-1"
    }
    $app.Uninstall()
}

Użyłem właściwości IdentifyingNumber do dopasowania zamiast nazwy, aby upewnić się, że odinstalowałem odpowiednią aplikację.

David Stetler
źródło
Po prostu cudowne to rozwiązanie
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
                }
            }
        }
    }
}

Nazwij to w ten sposób:

Uninstall-App "Autodesk Revit DB Link 2019"
Ehsan Iran-Nejad
źródło
6

Jedna linia kodu:

get-package *notepad* |% { & $_.Meta.Attributes["UninstallString"]}
Francesco Mantovani
źródło
3

Dokonam niewielkiego wkładu własnego. Musiałem usunąć listę pakietów z tego samego komputera. To jest scenariusz, który wymyśliłem.

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

Mam nadzieję, że okaże się to przydatne.

Zauważ, że jestem winien Davidowi Stetlerowi uznanie za ten skrypt, ponieważ jest on oparty na jego.

Ben Key
źródło
2

Oto skrypt PowerShell używający 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
źródło
Połączyłem to podejście z następującymi flagami , z jakiegoś powodu działa to lepiej niż inne podejścia dla mnie.
David Rogers
1

Na podstawie odpowiedzi Jeffa Hillmana:

Oto funkcja, którą możesz po prostu dodać do swojej profile.ps1lub zdefiniować w bieżącej sesji 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 + "'")
    }
}

Powiedzmy, że chcesz odinstalować Notepad ++ . Po prostu wpisz to w PowerShell:

> uninstall("notepad++")

Pamiętaj tylko, że Get-WmiObjectmoże to zająć trochę czasu, więc bądź cierpliwy!

Kolob Canyon
źródło
0

Posługiwać się:

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}"

Nie jest w pełni przetestowany, ale działał pod PowerShell 4.

Uruchomiłem plik PS1, jak widać tutaj. Pozwalając mu pobrać wszystkie systemy z AD i próbując odinstalować wiele aplikacji we wszystkich systemach.

Użyłem numeru identyfikacyjnego do wyszukania przyczyny oprogramowania danych wejściowych Davida Stetlera.

Nie testowany:

  1. Nie dodawanie identyfikatorów do wywołania funkcji w skrypcie, zamiast tego uruchamianie skryptu z identyfikatorami parametrów
  2. Wywołanie skryptu z więcej niż jedną nazwą komputera nie jest automatycznie pobierane z funkcji
  3. Pobieranie danych z potoku
  4. Używanie adresów IP do łączenia się z systemem

Czego to nie robi:

  1. Nie podaje żadnych informacji, czy oprogramowanie faktycznie zostało znalezione w danym systemie.
  2. Nie zawiera żadnych informacji o niepowodzeniu lub powodzeniu deinstalacji.

Nie mogłem użyć uninstall (). Próbując uzyskać błąd informujący mnie, że wywołanie metody dla wyrażenia, które ma wartość NULL, nie jest możliwe. Zamiast tego użyłem Remove-WmiObject, który wydaje się osiągać to samo.

UWAGA : Bez podania nazwy komputera usuwa oprogramowanie ze WSZYSTKICH systemów w usłudze Active Directory.

user3410872
źródło
0

W przypadku większości moich programów skrypty w tym poście spełniły swoje zadanie. Ale musiałem zmierzyć się ze starszym programem, którego nie mogłem usunąć za pomocą klasy msiexec.exe lub Win32_Product. (z jakiegoś powodu dostałem wyjście 0, ale program wciąż tam był)

Moim rozwiązaniem było użycie klasy Win32_Process:

z pomocą nickdnk ta komenda pozwala uzyskać ścieżkę do pliku deinstalacyjnego exe:

64-bitowy:

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

32-bitowy:

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

będziesz musiał wyczyścić ciąg wynikowy:

$uninstallPath = $unInstallPathReg[0].UninstallString
$uninstallPath = $uninstallPath -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
$uninstallPath = $uninstallPath .Trim()

teraz, gdy masz odpowiednią ścieżkę do pliku deinstalacji programu exe , możesz użyć tego polecenia:

$uninstallResult = (Get-WMIObject -List -Verbose | Where-Object {$_.Name -eq "Win32_Process"}).InvokeMethod("Create","$unInstallPath")

$ uninstallResult - będzie mieć kod zakończenia. 0 to sukces

powyższe polecenia można również uruchomić zdalnie - zrobiłem to za pomocą polecenia invoke, ale uważam, że dodanie argumentu -computername może działać

dsaydon
źródło