Wie kann ich eine Anwendung mit PowerShell deinstallieren?

136

Gibt es eine einfache Möglichkeit, mit PowerShell die Standardfunktion zum Hinzufügen oder Entfernen von Programmen zu verwenden , um eine vorhandene Anwendung zu deinstallieren ? Oder um zu überprüfen, ob die Anwendung installiert ist?

Rob Paterson
quelle

Antworten:

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

$app.Uninstall()

Bearbeiten: Rob hat einen anderen Weg gefunden, dies mit dem Filter-Parameter zu tun:

$app = Get-WmiObject -Class Win32_Product `
                     -Filter "Name = 'Software Name'"
Jeff Hillman
quelle
1
Das ist so ziemlich alles, ich würde sagen, dass es vielleicht besser ist, IdentifyingNumber anstelle des Namens zu verwenden, nur für den Fall.
Wannen
6
Nach ein wenig Recherche können Sie auch die -filter-Klausel von Get-WmiObject verwenden: $ app = Get-WmiObject -Class Win32_Product -filter "select * from Win32_Product WHERE name = 'Software Name'"
Rob Paterson
8
Beachten Sie, dass das Betrachten von WMI nur für Produkte funktioniert, die über eine MSI installiert wurden.
EBGreen
7
Die Aufzählung dieser WMI-Klasse dauert FÜR IMMER. Ich schlage Jeff vor, dass Sie Ihren Code aktualisieren, um Robs Tipp aufzunehmen.
halr9000
3
(gwmi Win32_Product | ? Name -eq "Software").uninstall() Ein bisschen Code Golf.
Roundar
51

EDIT: Im Laufe der Jahre hat diese Antwort einige positive Stimmen bekommen. Ich möchte einige Kommentare hinzufügen. Ich habe PowerShell seitdem nicht mehr verwendet, erinnere mich jedoch an einige Probleme:

  1. Wenn es mehr Übereinstimmungen als 1 für das folgende Skript gibt, funktioniert es nicht und Sie müssen den PowerShell-Filter anhängen, der die Ergebnisse auf 1 begrenzt. Ich glaube, es ist, -First 1aber ich bin nicht sicher. Fühlen Sie sich frei zu bearbeiten.
  2. Wenn die Anwendung nicht von MSI installiert wird, funktioniert sie nicht. Der Grund, warum es wie folgt geschrieben wurde, ist, dass es die MSI so ändert, dass sie ohne Intervention deinstalliert wird. Dies ist nicht immer der Standardfall, wenn die native Deinstallationszeichenfolge verwendet wird.

Die Verwendung des WMI-Objekts dauert ewig. Dies ist sehr schnell, wenn Sie nur den Namen des Programms kennen, das Sie deinstallieren möchten.

$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
quelle
1
Danke dafür! Ich versuche dies zu verwenden, -like "appNam*"da die Version im Namen enthalten ist und sich ändert, aber das Programm scheint nicht gefunden zu werden. Irgendwelche Ideen?
NSouth
1
Suchen Sie nach der ähnlichen Funktion für Powershell und finden Sie heraus, welcher Filter verwendet werden soll, um die richtige Übereinstimmung mit Ihrer Zeichenfolge zu erzielen. Verwenden Sie einfach die Shell zum Testen, und sobald Sie es richtig gemacht haben, ersetzen Sie das -match :)
nickdnk
2
Das ist Gold. Persönlich entferne ich das 'b' aus dem '/ qb', damit Sie keine Dialoge sehen müssen.
WhiteHotLoveTiger
Viel schneller :-)
Oscar Foley
3
Ich habe daraus ein .ps1-Skript mit Eingabeaufforderung und der Information "Was ich deinstallieren werde" gemacht. gist.github.com/chrisfcarroll/e38b9ffcc52fa9d4eb9ab73b13915f5a
Chris F Carroll
34

Um die zweite Methode in Jeff Hillmans Beitrag zu korrigieren, können Sie entweder Folgendes ausführen:

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

Oder

$app = Get-WmiObject -Class Win32_Product `
                     -Filter "Name = 'Software Name'"
Robert Wagner
quelle
Nur ein Heads-up ... Ich fand, dass die Verwendung der Option "-Query" anstelle der Option "-Filter" kein WmiObject zurückgab, sodass es keine "Deinstallations" -Methode gab.
Doug J. Huras
7

Ich habe herausgefunden, dass die Win32_Product-Klasse nicht empfohlen wird, da sie Reparaturen auslöst und nicht abfrageoptimiert ist. Quelle

Ich habe diesen Beitrag von Sitaram Pamarthi mit einem Skript zum Deinstallieren gefunden, wenn Sie die App-Anleitung kennen. Er liefert auch ein weiteres Skript, um hier sehr schnell nach Apps zu suchen .

Verwenden Sie Folgendes :. \ 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
quelle
7

Um diesem Beitrag etwas hinzuzufügen, musste ich in der Lage sein, Software von mehreren Servern zu entfernen. Ich habe Jeffs Antwort benutzt, um mich dazu zu führen:

Zuerst habe ich eine Liste von Servern erhalten, ich habe eine AD- Abfrage verwendet, aber Sie können das Array von Computernamen angeben, wie Sie möchten:

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

Dann habe ich sie durchlaufen und der gwmi-Abfrage den Parameter -computer hinzugefügt:

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

Ich habe die IdentifyingNumber-Eigenschaft anstelle von name verwendet, um sicherzugehen, dass ich die richtige Anwendung deinstalliert habe.

David Stetler
quelle
Einfach schön diese Lösung
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
                }
            }
        }
    }
}

Nennen Sie es so:

Uninstall-App "Autodesk Revit DB Link 2019"
Ehsan Iran-Nejad
quelle
6

Eine Codezeile:

get-package *notepad* |% { & $_.Meta.Attributes["UninstallString"]}
Francesco Mantovani
quelle
3

Ich werde meinen eigenen kleinen Beitrag leisten. Ich musste eine Liste von Paketen vom selben Computer entfernen. Dies ist das Skript, das ich mir ausgedacht habe.

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

Ich hoffe, das erweist sich als nützlich.

Beachten Sie, dass ich David Stetler die Anerkennung für dieses Skript schulde, da es auf seinem basiert.

Ben Key
quelle
2

Hier ist das PowerShell-Skript mit 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
quelle
Ich habe diesen Ansatz mit den folgenden Flags kombiniert. Aus irgendeinem Grund funktioniert dies besser als die anderen Ansätze für mich.
David Rogers
1

Basierend auf Jeff Hillmans Antwort:

Hier ist eine Funktion, die Sie einfach zu Ihrer hinzufügen profile.ps1oder in der aktuellen PowerShell-Sitzung definieren können:

# 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 + "'")
    }
}

Angenommen, Sie wollten Notepad ++ deinstallieren . Geben Sie dies einfach in PowerShell ein:

> uninstall("notepad++")

Seien Sie sich nur bewusst, dass Get-WmiObjectdies einige Zeit dauern kann. Seien Sie also geduldig!

Kolob Canyon
quelle
0

Verwenden:

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

Es ist nicht vollständig getestet, wurde jedoch unter PowerShell 4 ausgeführt.

Ich habe die PS1-Datei so ausgeführt, wie sie hier zu sehen ist. Lassen Sie es alle Systeme aus dem AD abrufen und versuchen Sie, mehrere Anwendungen auf allen Systemen zu deinstallieren.

Ich habe die IdentifyingNumber verwendet, um nach der Software-Ursache für die Eingabe von David Stetlers zu suchen.

Nicht getestet:

  1. Fügen Sie dem Aufruf der Funktion im Skript keine IDs hinzu, sondern starten Sie das Skript mit Parameter-IDs
  2. Das Aufrufen des Skripts mit mehr als einem Computernamen wird nicht automatisch von der Funktion abgerufen
  3. Daten aus der Pipe abrufen
  4. Verwenden von IP-Adressen zum Herstellen einer Verbindung zum System

Was es nicht tut:

  1. Es gibt keine Informationen darüber, ob die Software tatsächlich auf einem bestimmten System gefunden wurde.
  2. Es gibt keine Informationen über Fehler oder Erfolg der Deinstallation.

Ich konnte uninstall () nicht verwenden. Beim Versuch, dass eine Fehlermeldung angezeigt wird, ist es nicht möglich, eine Methode für einen Ausdruck mit dem Wert NULL aufzurufen. Stattdessen habe ich Remove-WmiObject verwendet, was anscheinend dasselbe bewirkt.

VORSICHT : Ohne Angabe eines Computernamens wird die Software von ALLEN Systemen im Active Directory entfernt.

user3410872
quelle
0

Für die meisten meiner Programme haben die Skripte in diesem Beitrag den Job gemacht. Ich musste mich jedoch einem Legacy-Programm stellen, das ich mit der Klasse msiexec.exe oder Win32_Product nicht entfernen konnte. (Aus irgendeinem Grund habe ich Exit 0 bekommen, aber das Programm war noch da)

Meine Lösung bestand darin, die Win32_Process-Klasse zu verwenden:

Mit Hilfe von nickdnk soll mit diesem Befehl der Pfad der exe-Deinstallationsdatei abgerufen werden:

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

Sie müssen die Ergebniszeichenfolge bereinigen:

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

Wenn Sie das entsprechende Programm haben, deinstallieren Sie den exe-Dateipfad. Verwenden Sie diesen Befehl:

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

$ uninstallResult - hat den Exit-Code. 0 ist Erfolg

Die oben genannten Befehle können auch remote ausgeführt werden. Ich habe sie mit dem Befehl invoke ausgeführt, glaube jedoch, dass das Hinzufügen des Arguments -computername funktionieren kann

Dsaydon
quelle