Come posso disinstallare un'applicazione usando PowerShell?


136

Esiste un modo semplice per agganciare la funzionalità standard " Installazione applicazioni " utilizzando PowerShell per disinstallare un'applicazione esistente ? O per verificare se l'applicazione è installata?

Risposte:


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

$app.Uninstall()

Modifica: Rob ha trovato un altro modo per farlo con il parametro Filter:

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

1
Questo è abbastanza, direi che potrebbe essere meglio usare IdentifyingNumber piuttosto che il nome, per ogni evenienza.
Vasche

6
Dopo un po 'di ricerche puoi anche usare la clausola -filter di Get-WmiObject: $ app = Get-WmiObject -Class Win32_Product -filter "seleziona * da Win32_Product DOVE nome =' Nome software '"
Rob Paterson

8
Si noti che guardando WMI funzionerà solo con prodotti installati tramite MSI.
EBGreen

7
Questa classe WMI impiega SEMPRE per enumerare. Suggerisco a Jeff di aggiornare il codice per includere il suggerimento di Rob.
halr9000,

4
(gwmi Win32_Product | ? Name -eq "Software").uninstall() Un piccolo codice golf.
roundar

51

EDIT: Nel corso degli anni questa risposta ha ottenuto parecchi voti. Vorrei aggiungere alcuni commenti. Da allora non utilizzo PowerShell, ma ricordo di aver osservato alcuni problemi:

  1. Se esistono più corrispondenze di 1 per lo script seguente, non funziona e devi aggiungere il filtro PowerShell che limita i risultati a 1. Credo che sia -First 1 ma non ne sono sicuro. Sentiti libero di modificare.
  2. Se l'applicazione non è installata da MSI, non funziona. Il motivo per cui è stato scritto come di seguito è perché modifica l'MSI per disinstallarlo senza intervento, che non è sempre il caso predefinito quando si utilizza la stringa di disinstallazione nativa.

L'uso dell'oggetto WMI richiede un'eternità. Questo è molto veloce se conosci solo il nome del programma che desideri disinstallare.

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

1
Grazie per questo! Sto provando a usarlo -like "appNam*"perché la versione è nel nome e cambia, ma non sembra trovare il programma. Qualche idea?
NSouth,

1
Cerca la funzione simile a PowerShell, scopri quale filtro usare e come farlo corrispondere correttamente alla tua stringa. Basta usare la shell per testare e, una volta capito bene, sostituire la corrispondenza :)
nickdnk,

2
Questo è oro Personalmente, rimuovo la 'b' da '/ qb' in modo da non dover vedere alcuna finestra di dialogo.
WhiteHotLoveTiger

Molto più veloce :-)
Oscar Foley,

3
Ho trasformato questo in uno script .ps1 con prompt e informazioni "cosa sto per disinstallare". gist.github.com/chrisfcarroll/e38b9ffcc52fa9d4eb9ab73b13915f5a
Chris F Carroll

34

Per sistemare il secondo metodo nel post di Jeff Hillman, puoi fare un:

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

O

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

Solo un avvertimento ... Ho scoperto che l'uso dell'opzione "-Query" invece dell'opzione "-Filter" non ha restituito un WmiObject, quindi non ha un metodo di "disinstallazione".
Doug J. Huras,

7

Ho scoperto che la classe Win32_Product non è consigliata perché attiva le riparazioni e non è ottimizzata per le query. fonte

Ho trovato questo post di Sitaram Pamarthi con uno script da disinstallare se conosci l'app guid. Fornisce anche un altro script per cercare app molto velocemente qui .

Utilizzare in questo modo:. \ 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

Per aggiungere un po 'a questo post, dovevo essere in grado di rimuovere il software da più server. Ho usato la risposta di Jeff per guidarmi a questo:

Per prima cosa ho ottenuto un elenco di server, ho usato una query AD , ma puoi fornire l'array di nomi di computer come desideri:

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

Poi li ho passati in loop, aggiungendo il parametro -computer alla query gwmi:

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

Ho usato la proprietà IdentifyingNumber per abbinare invece di nome, solo per essere sicuro che stavo disinstallando l'applicazione corretta.


Semplicemente adorabile questa soluzione
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
                }
            }
        }
    }
}

Chiamalo in questo modo:

Uninstall-App "Autodesk Revit DB Link 2019"


3

Farò il mio piccolo contributo. Avevo bisogno di rimuovere un elenco di pacchetti dallo stesso computer. Questa è la sceneggiatura che mi è venuta in mente.

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

Spero che questo si riveli utile.

Nota che devo a David Stetler il merito di questo script poiché si basa sul suo.


2

Ecco lo script di PowerShell usando 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"

Ho combinato questo approccio con le seguenti bandiere , per qualche ragione funziona meglio degli altri approcci per me.
David Rogers,

1

Basato sulla risposta di Jeff Hillman:

Ecco una funzione che puoi semplicemente aggiungere alla tua profile.ps1o definire nella sessione corrente di 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 + "'")
    }
}

Diciamo che volevi disinstallare Notepad ++ . Basta digitare questo in PowerShell:

> uninstall("notepad++")

Basta essere consapevoli del fatto che Get-WmiObjectpuò richiedere del tempo, quindi sii paziente!


0

Uso:

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

Non è completamente testato, ma è stato eseguito con PowerShell 4.

Ho eseguito il file PS1 come è visto qui. Consentendo di recuperare tutti i sistemi dall'AD e provare a disinstallare più applicazioni su tutti i sistemi.

Ho usato il numero di identificazione per cercare la causa del software dell'input di David Stetlers.

Non testato:

  1. Non aggiungendo ID alla chiamata della funzione nello script, ma avviando lo script con ID parametro
  2. Chiamare lo script con più di 1 nome computer non recuperato automaticamente dalla funzione
  3. Recupero dei dati dalla pipe
  4. Utilizzo degli indirizzi IP per connettersi al sistema

Cosa non fa:

  1. Non fornisce alcuna informazione se il software è stato effettivamente trovato su un determinato sistema.
  2. Non fornisce alcuna informazione sull'errore o sul successo della disinstallazione.

Non sono stato in grado di utilizzare uninstall (). Provando a ricevere un errore che mi dice che non è possibile chiamare un metodo per un'espressione che ha un valore NULL. Invece ho usato Remove-WmiObject, che sembra realizzare lo stesso.

ATTENZIONE : senza un nome computer dato, il software viene rimosso da TUTTI i sistemi in Active Directory.


0

Per la maggior parte dei miei programmi gli script in questo post hanno fatto il lavoro. Ma ho dovuto affrontare un programma legacy che non potevo rimuovere usando la classe msiexec.exe o Win32_Product. (per qualche motivo ho ottenuto l'uscita 0 ma il programma era ancora lì)

La mia soluzione era usare la classe Win32_Process:

con l'aiuto di nickdnk questo comando serve per ottenere il percorso del file exe di disinstallazione:

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

dovrai pulire la stringa del risultato:

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

ora quando si dispone del relativo programma disinstallare il percorso del file exe è possibile utilizzare questo comando:

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

$ uninstallResult - avrà il codice di uscita. 0 è successo

i comandi precedenti possono anche essere eseguiti in remoto - l'ho fatto usando il comando invoke ma credo che l'aggiunta dell'argomento -computername possa funzionare

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.