Comment puis-je désinstaller une application à l'aide de PowerShell?

136

Existe-t-il un moyen simple de se connecter à la fonctionnalité standard « Ajouter ou supprimer des programmes » à l'aide de PowerShell pour désinstaller une application existante ? Ou pour vérifier si l'application est installée?

Rob Paterson
la source

Réponses:

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

$app.Uninstall()

Edit: Rob a trouvé un autre moyen de le faire avec le paramètre Filter:

$app = Get-WmiObject -Class Win32_Product `
                     -Filter "Name = 'Software Name'"
Jeff Hillman
la source
1
C'est à peu près tout, je dirais qu'il peut être préférable d'utiliser IdentifyingNumber plutôt que le nom, juste au cas où.
Tubs
6
Après quelques recherches, vous pouvez également utiliser la clause -filter de Get-WmiObject: $ app = Get-WmiObject -Class Win32_Product -filter "select * from Win32_Product WHERE name = 'Software Name'"
Rob Paterson
8
Notez que la recherche sur WMI ne fonctionnera que pour les produits installés via un MSI.
EBGreen
7
Cette classe WMI prend FOREVER pour énumérer. Je suggère à Jeff de mettre à jour votre code pour inclure le conseil de Rob.
halr9000 le
4
(gwmi Win32_Product | ? Name -eq "Software").uninstall() Un peu de golf codé.
roundar
51

EDIT: Au fil des ans, cette réponse a reçu un certain nombre de votes positifs. Je voudrais ajouter quelques commentaires. Je n'ai pas utilisé PowerShell depuis, mais je me souviens avoir observé quelques problèmes:

  1. S'il y a plus de correspondances que 1 pour le script ci-dessous, cela ne fonctionne pas et vous devez ajouter le filtre PowerShell qui limite les résultats à 1. Je crois que c'est -First 1 mais je ne suis pas sûr. N'hésitez pas à modifier.
  2. Si l'application n'est pas installée par MSI, elle ne fonctionne pas. La raison pour laquelle il a été écrit comme ci-dessous est qu'il modifie le MSI pour le désinstaller sans intervention, ce qui n'est pas toujours le cas par défaut lors de l'utilisation de la chaîne de désinstallation native.

L'utilisation de l'objet WMI prend une éternité. C'est très rapide si vous connaissez simplement le nom du programme que vous souhaitez désinstaller.

$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
la source
1
Merci pour cela! J'essaie de l'utiliser avec -like "appNam*"puisque la version est dans le nom et qu'elle change, mais il ne semble pas trouver le programme. Des idées?
NSouth
1
Recherchez la fonction -like pour powershell, découvrez quel filtre utiliser et comment le faire correspondre correctement à votre chaîne. Utilisez simplement le shell pour tester, et une fois que vous avez réussi, remplacez -match :)
nickdnk
2
C'est de l'or. Personnellement, je supprime le 'b' du '/ qb' pour que vous n'ayez pas à voir de dialogue.
WhiteHotLoveTiger
Beaucoup plus rapide :-)
Oscar Foley
3
J'ai transformé cela en un script .ps1 avec une invite et une information "ce que je suis sur le point de désinstaller". gist.github.com/chrisfcarroll/e38b9ffcc52fa9d4eb9ab73b13915f5a
Chris F Carroll
34

Pour corriger la deuxième méthode dans l'article de Jeff Hillman, vous pouvez soit faire un:

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

Ou

$app = Get-WmiObject -Class Win32_Product `
                     -Filter "Name = 'Software Name'"
Robert Wagner
la source
Juste un avertissement ... J'ai trouvé que l'utilisation de l'option "-Query" au lieu de l'option "-Filter" ne renvoyait pas de WmiObject, donc il n'y avait pas de méthode "de désinstallation".
Doug J.Huras
7

J'ai découvert que la classe Win32_Product n'est pas recommandée car elle déclenche des réparations et n'est pas optimisée pour la requête. La source

J'ai trouvé ce post de Sitaram Pamarthi avec un script à désinstaller si vous connaissez l'application guid. Il fournit également un autre script pour rechercher des applications très rapidement ici .

Utilisez comme ceci:. \ 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
la source
7

Pour ajouter un peu à cet article, je devais être capable de supprimer des logiciels de plusieurs serveurs. J'ai utilisé la réponse de Jeff pour m'amener à ceci:

J'ai d'abord eu une liste de serveurs, j'ai utilisé une requête AD , mais vous pouvez fournir le tableau de noms d'ordinateurs comme vous le souhaitez:

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

Ensuite, je les ai parcourus, en ajoutant le paramètre -computer à la requête gwmi:

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

J'ai utilisé la propriété IdentifyingNumber pour faire correspondre au lieu du nom, juste pour être sûr de désinstaller la bonne application.

David Stetler
la source
Tout simplement adorable cette solution
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
                }
            }
        }
    }
}

Appelez-le ainsi:

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

Une ligne de code:

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

Je ferai ma propre petite contribution. J'avais besoin de supprimer une liste de paquets du même ordinateur. C'est le script que j'ai imaginé.

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

J'espère que cela se révélera utile.

Notez que je dois à David Stetler le mérite de ce script car il est basé sur le sien.

Ben Key
la source
2

Voici le script PowerShell utilisant 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
la source
J'ai combiné cette approche avec les indicateurs suivants , pour une raison quelconque, cela fonctionne mieux que les autres approches pour moi.
David Rogers
1

Basé sur la réponse de Jeff Hillman:

Voici une fonction que vous pouvez simplement ajouter à votre profile.ps1ou définir dans la session PowerShell actuelle:

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

Disons que vous vouliez désinstaller Notepad ++ . Tapez simplement ceci dans PowerShell:

> uninstall("notepad++")

Sachez simplement que cela Get-WmiObjectpeut prendre du temps, alors soyez patient!

Canyon de Kolob
la source
0

Utilisation:

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

Il n'est pas entièrement testé, mais il a fonctionné sous PowerShell 4.

J'ai exécuté le fichier PS1 tel qu'il est vu ici. Laisser récupérer tous les systèmes de l' AD et essayer de désinstaller plusieurs applications sur tous les systèmes.

J'ai utilisé le IdentifyingNumber pour rechercher la cause logicielle de l'entrée de David Stetlers.

Pas testé:

  1. Ne pas ajouter d'id à l'appel de la fonction dans le script, mais démarrer le script avec des ID de paramètre
  2. Appel du script avec plus d'un nom d'ordinateur non automatiquement récupéré de la fonction
  3. Récupération des données du tuyau
  4. Utilisation d'adresses IP pour se connecter au système

Ce qu'il ne fait pas:

  1. Il ne donne aucune information si le logiciel a réellement été trouvé sur un système donné.
  2. Il ne donne aucune information sur l'échec ou le succès de la désinstallation.

Je n'ai pas pu utiliser uninstall (). Essayer que j'ai eu une erreur me disant que l'appel d'une méthode pour une expression qui a une valeur NULL n'est pas possible. Au lieu de cela, j'ai utilisé Remove-WmiObject, qui semble accomplir la même chose.

PRÉCAUTION : Sans nom d'ordinateur donné, il supprime le logiciel de TOUS les systèmes dans Active Directory.

user3410872
la source
0

Pour la plupart de mes programmes, les scripts de cet article ont fait le travail. Mais j'ai dû faire face à un programme hérité que je ne pouvais pas supprimer en utilisant la classe msiexec.exe ou Win32_Product. (pour une raison quelconque, j'ai obtenu la sortie 0 mais le programme était toujours là)

Ma solution était d'utiliser la classe Win32_Process:

avec l'aide de nickdnk, cette commande consiste à obtenir le chemin du fichier de désinstallation exe:

64 bits:

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

32 bits:

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

vous devrez nettoyer la chaîne de résultat:

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

maintenant, lorsque vous avez le chemin du fichier exe de désinstallation du programme approprié , vous pouvez utiliser cette commande:

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

$ uninstallResult - aura le code de sortie. 0 est le succès

les commandes ci-dessus peuvent également s'exécuter à distance - je l'ai fait en utilisant la commande invoke mais je crois que l'ajout de l'argument -computername peut fonctionner

Dsaydon
la source