Lister les paquets et leur état

Questions about WAPT Packaging / Requêtes et aides autour des paquets Wapt.
Règles du forum
Règles du forum communautaire
* English support on www.reddit.com/r/wapt
* Le support communautaire en français se fait sur ce forum
* Merci de préfixer le titre du topic par [RESOLU] s'il est résolu.
* Merci de ne pas modifier un topic qui est taggé [RESOLU]. Ouvrez un nouveau topic en référençant l'ancien
* Préciser version de WAPT installée, version complète ET numéro de build (2.2.1.11957 / 2.2.2.12337 / etc.) AINSI QUE l'édition Enterprise / Discovery
* Les versions 1.8.2 et antérieures ne sont plus maintenues. Les seules questions acceptées vis à vis de la version 1.8.2 sont liés à la mise à jour vers une version supportée (2.1, 2.2, etc.)
* Préciser OS du serveur (Linux / Windows) et version (Debian Buster/Bullseye - CentOS 7 - Windows Server 2012/2016/2019)
* Préciser OS de la machine d'administration/création des paquets et de la machine avec l'agent qui pose problème le cas échéant (Windows 7 / 10 / 11 / Debian 11 / etc.)
* Eviter de poser plusieurs questions lors de l'ouverture de topic, sinon il risque d'être ignorer. Si plusieurs sujet, ouvrir plusieurs topic, et de préférence les uns après les autres et pas tous en même temps (ie ne pas spammer le forum).
* Inclure directement les morceaux de code, les captures d'écran et autres images directement dans le post. Les liens vers les pastebin, les bitly et autres sites tierces seront systématiquement supprimés.
* Comme tout forum communautaire, le support est fait bénévolement par les membres. Si vous avez besoin d'un support commercial, vous pouvez contacter le service commercial Tranquil IT au 02.40.97.57.55
Mikael S
Messages : 22
Inscription : 20 janv. 2025 - 15:54

28 nov. 2025 - 11:19

Bonjour,

Existe-t-il un moyen de lister tous les paquets installés sur une machine ainsi que leur état et leur audit depuis un setup.py ?

L'idée serait de mettre en place des remédiations automatiques dans certains cas avec des installations problématiques.



Cordialement,
b.ald
Messages : 15
Inscription : 04 oct. 2025 - 22:59

02 déc. 2025 - 07:18

Bonjour,

je ne suis pas très sûr de ce que vous cherchez à faire mais dans un de mes paquets j'ai quelque chose dans le genre :

Code : Tout sélectionner

package_list = WAPT.installed_package_names()      # recup les paquets installés sur la machine
for package in sorted(package_list):
    WAPT.audit(package, force=False)               # fait un audit du paquet pour chaque paquet présent dans la liste



Après.. tout cela est déjà visible dans la console WAPT.

Cdt.
WAPT Discovery -- 2.6.1.17705 -- SRV Ubuntu 24.04 arm64
WAPT Enterprise -- 2.6.1.17576 -- SRV Ubuntu 22.04
WAPT Enterprise -- 2.6.1.17576 -- SRV RHEL 9 --//-- Dépôts secondaires -- Rocky 9
adm : W11pro
Mikael S
Messages : 22
Inscription : 20 janv. 2025 - 15:54

08 déc. 2025 - 16:28

Bonjour,

Cela ne me permet pas d'obtenir le statut.

L'idée, c'est par exemple, je veux installer les microsoft visual c++ 2015-2022, mais windows étant un outil formidable, l'installation du msi requiert de désinstaller l'ancien, mais le fichier d'installation a depuis été supprimé.

L'installateur part donc en erreur. Il est impossible de désinstaller, même problème, il faut donc purger la base de registre pour faire oublier à windows la présence de cette installation et donc d'en faire une nouvelle.
Ce type de cas se produit très souvent sur plein de produit.

En faisant un paquet médiation, je liste toutes les erreurs en cours et je lance une remédiation. Dans l'exemple, purger la base de registre pour permettre ensuite la bonne installation.

Actuellement, nous l'avons dans la console, et nous le faisons à la main. Mais avec 10 000 postes à gérer dont 450 avec des erreurs, c'est vite intenable.
On a de tout, du keepassxc, seafile, jabra, etc.
Certaines erreurs sont dues à notre précédente solution et n'apparaissent pas sur les postes installés avec WAPT.

Bref, l'idée est de gérer tout ça au maximum automatiquement et sans être derrière les postes tout le temps.
Sachant qu'un poste corrigé ne veut pas dire que le problème ne se posera pas à la prochaine mise à jour. Cela dépend beaucoup d'installateurs (souvent très bien codé ! :mrgreen: )
florentR2
Messages : 100
Inscription : 13 févr. 2020 - 17:23

08 déc. 2025 - 16:34

C'est très intéressant car je viens justement de passer pas mal de temps pour trouver une solution pour le client Nextcloud qui nous produit pas mal d'erreur de ce type.
J'ai corrigé seulement ce package avec des try catch mais votre idée d'un paquet de remédiation général est pas mal, je m'abonne au topic si y'a une solution qui tombe.
Je purge ceci dans le registre :

Code : Tout sélectionner

HKLM\SOFTWARE\\Microsoft\Windows\CurrentVersion\Uninstall\{guid}
HKLM\SOFTWARE\Classes\Installer\Products\{guid_key_wininstaller}
b.ald
Messages : 15
Inscription : 04 oct. 2025 - 22:59

15 déc. 2025 - 14:13

Bonjour,

par "status", est-ce si le paquet est en "OK"/"WARNING"/"ERROR" ?

Si c'est le cas, alors essayez peut-être :

Code : Tout sélectionner

package = WAPT.is_installed('nom_de_votre_paquet')
package_status = package['install_status']                          # recupère si status OK/WARNING/ERROR
un simple print devrait afficher le status :

Code : Tout sélectionner

print(package_status)
mais vous pouvez ensuite faire par exemple un

Code : Tout sélectionner

if package_status == 'ERROR' : 
       ce que vous voulez faire ensuite



edit : après il faut bien entendu que le paquet en question soit déjà présent sur la machine
WAPT Discovery -- 2.6.1.17705 -- SRV Ubuntu 24.04 arm64
WAPT Enterprise -- 2.6.1.17576 -- SRV Ubuntu 22.04
WAPT Enterprise -- 2.6.1.17576 -- SRV RHEL 9 --//-- Dépôts secondaires -- Rocky 9
adm : W11pro
Mikael S
Messages : 22
Inscription : 20 janv. 2025 - 15:54

03 févr. 2026 - 13:24

Il doit peut-être avoir plus simple, mais ceci marche pour avoir la liste des paquets dont l'installation est en erreur.

Code : Tout sélectionner

for package in WAPT.waptdb.installed_packages_inventory():
        if package[5] == 'ERROR':
            print(package[1])
Reste encore à tenter de corriger en trouvant quoi corriger
Mikael S
Messages : 22
Inscription : 20 janv. 2025 - 15:54

16 mars 2026 - 13:18

C'est encore en test chez nous, mais ça donne ça

Je garde en mémoire dans un json tous les paquets tenté pour ne faire qu'une seule tentative.

Cela donne pour l'instant de bons résultats

Code : Tout sélectionner

# -*- coding: utf-8 -*-
from setuphelpers import *
import json
import datetime
import winreg
import re
from contextlib import suppress
import itertools

# Dictionnaire package wapt => nom de l'application en format regex
dict_package_app = {
    "tis-chrome" : "Google Chrome",
    "tis-element" : "Element",
    "tis-googleearth" : "Google Earth Pro",
    "tis-glpi-agent" : "GLPI agent [0-9.]+",
    "tis-keepassxc" : "KeePassXC",
    "tis-libreoffice-fresh" : "LibreOffice [0-9.]+",
    "tis-microsoft-edge" : "Microsoft Edge",
    "tis-onlyoffice-desktop" : "ONLYOFFICE [0-9.]+ \(x64\)",
    "tis-oracle-java8-jre-free" : "Java 8 Update [0-9]+(| x64 bit)",
    "tis-pdf24-creator" : "PDF24 Creator",
    "tis-seafile" : "Seafile [0-9.]+",
    "tis-microsoft-teams" : "Teams Machine-Wide Installer",
    "tis-teamviewer" : "TeamViewer",
    "tis-vcredist2015-2022" : "Microsoft Visual C\+\+ (2015-2022 Redistributable \(x(86|64)\)|2022 X64 Additional Runtime) - [0-9.]+",
    "tis-wazo" : "Wazo Desktop",
    "tis-webex" : "Webex",
    "tis-webview2" : "Microsoft Edge WebView2 Runtime",
    "tis-zoom" : "Zoom Workplace \(64-bit\)"
}

json_file = r"C:\Windows\wapt\autofix.json"

def install():
    generate_json()

def audit():
    if not isfile(json_file):
        generate_json()

    with open(json_file) as file:
        status = json.load(file)

    return_value = "OK"
    packages_installed = set() # Contient la liste des paquets installés pour purge le json ensuite
    for wapt_installed_package in WAPT.waptdb.installed_status(include_errors=True):
        packages_installed.add(wapt_installed_package['package'])

        # Gestion des installation en erreur si le paquet est déclaré dans dict_package_app
        # Tentative de purge de la des anciennes installations de la base de registre
        if wapt_installed_package['install_status'] == "ERROR" and wapt_installed_package['package'] in dict_package_app:
            if status['install'].get(wapt_installed_package['package'], False):
                print(f"Réparation de l'installation du paquet {wapt_installed_package['package']} déjà tenté")
                return_value = "ERROR"
            else:
                print(f"Tentative de réparation de l'installation du paquet {wapt_installed_package['package']}")
                if WAPT.waptserver.available():
                    status['install'][wapt_installed_package['package']] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

                    delete_key("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 'DisplayName', dict_package_app[wapt_installed_package['package']])
                    delete_key("SOFTWARE\\Classes\\Installer\\Products", 'ProductName', dict_package_app[wapt_installed_package['package']])

                    try:
                        WAPT.install(wapt_installed_package['package'])
                    except:
                        print(f"Erreur d'installation de {wapt_installed_package['package']}")
                    if return_value != "ERROR":
                        return_value = "WARNING"
                else:
                    print("Serveur WAPT non joignable - une tentative sera faite au prochain audit")

        # Si le paquet n'est pas en erreur, on le retire du json s'il existe
        elif status['install'].get(wapt_installed_package['package'], False):
            del status['install'][wapt_installed_package['package']]

        # Gestion des audit en erreur
        # Tentative d'une installation forcée
        if wapt_installed_package['last_audit_status'] == "ERROR" and wapt_installed_package['package'] != "tis-autofix-installation":
            if status['audit'].get(wapt_installed_package['package'], False):
                print(f"Réparation de l'audit du paquet {wapt_installed_package['package']} déjà tenté")
                return_value = "ERROR"
            else:
                print(f"Tentative de réparation de l'audit du paquet {wapt_installed_package['package']}")
                if WAPT.waptserver.available():
                    status['audit'][wapt_installed_package['package']] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    try:
                        WAPT.install(wapt_installed_package['package'], force=True)
                    except:
                        print(f"Erreur d'installation de {wapt_installed_package['package']}")

                    if return_value != "ERROR":
                        return_value = "WARNING"
                else:
                    print("Serveur WAPT non joignable - une tentative sera faite au prochain audit")

        # Si le paquet n'est pas en erreur, on le retire du json s'il existe
        elif status['audit'].get(wapt_installed_package['package'], False):
            del status['audit'][wapt_installed_package['package']]

    # Purge des anciennes tentative si le paquet n'est plus sur la machine
    for wapt_installed_package in status['install'].copy():
        if wapt_installed_package not in packages_installed:
            del  status['install'][wapt_installed_package]

    for wapt_installed_package in status['audit'].copy():
        if wapt_installed_package not in packages_installed:
            del status['audit'][wapt_installed_package]

    with open(json_file, 'w') as autofix:
        json.dump(status, autofix)

    return return_value

def uninstall():
    if isfile(json_file):
        remove_file(json_file)

def generate_json():
    if not isdir(r'C:\Windows\wapt'):
        mkdirs(r'C:\Windows\wapt')

    status = {}
    status['install'] = {}
    status['audit'] = {}

    with open(json_file, 'w') as autofix:
        json.dump(status, autofix)

def delete_key(key_uninstall, key_value, key_search):
    for subkey in subkeys(key_uninstall):
        appkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, rf"{key_uninstall}\{subkey}", 0, winreg.KEY_READ)
        try:
            key_find = reg_getvalue(appkey, key_value, '')

            if re.match(f"^{key_search}$", key_find):
                print(f'Suppression clé {key_uninstall}\{subkey}')
                winreg.DeleteKey(appkey, '')
        except FileNotFoundError:
            pass

def subkeys(path, hkey=HKEY_LOCAL_MACHINE):
    with suppress(WindowsError), winreg.OpenKey(hkey, path, 0, winreg.KEY_READ) as k:
        for i in itertools.count():
            yield winreg.EnumKey(k, i)
Dernière modification par Mikael S le 24 mars 2026 - 07:59, modifié 1 fois.
florentR2
Messages : 100
Inscription : 13 févr. 2020 - 17:23

16 mars 2026 - 13:58

Merci pour le partage !
Mikael S a écrit : 16 mars 2026 - 13:18 C'est encore en test chez nous, mais ça donne ça

Je garde en mémoire dans un json tous les paquets tenté pour ne faire qu'une seule tentative.

Cela donne pour l'instant de bons résultats

Code : Tout sélectionner

# -*- coding: utf-8 -*-
from setuphelpers import *
import json
import datetime
import winreg
import re

# Dictionnaire package wapt => nom de l'application en format regex
dict_package_app = {
    "tis-chrome" : "Google Chrome",
    "tis-element" : "Element",
    "tis-googleearth" : "Google Earth Pro",
    "tis-glpi-agent" : "GLPI agent [0-9.]+",
    "tis-keepassxc" : "KeePassXC",
    "tis-libreoffice-fresh" : "LibreOffice [0-9.]+",
    "tis-microsoft-edge" : "Microsoft Edge",
    "tis-oracle-java8-jre-free" : "Java 8 Update [0-9]+(| x64 bit)",
    "tis-pdf24-creator" : "PDF24 Creator",
    "tis-seafile" : "Seafile [0-9.]+",
    "tis-microsoft-teams" : "Teams Machine-Wide Installer",
    "tis-teamviewer" : "TeamViewer",
    "tis-vcredist2015-2022" : "Microsoft Visual C++ 2015-2022 Redistributable \(x(86|64)\) - [0-9.]+",
    "tis-wazo" : "Wazo Desktop",
    "tis-webex" : "Webex",
    "tis-webview2" : "Microsoft Edge WebView2 Runtime",
    "tis-zoom" : "Zoom Workplace \(64-bit\)"
}
json_file = r"C:\Windows\wapt\autofix.json"

def install():
    if not isfile(json_file) or force:
        generate_json()

def audit():
    if not isfile(json_file):
        generate_json()

    with open(json_file) as file:
        status = json.load(file)

    return_value = "OK"
    packages_installed = set() # Contient la liste des paquets installés pour purge le json ensuite
    for wapt_installed_package in WAPT.waptdb.installed_status(include_errors=True):
        packages_installed.add(wapt_installed_package['package'])

        # Gestion des installation en erreur si le paquet est déclaré dans dict_package_app
        # Tentative de purge de la des anciennes installations de la base de registre
        if wapt_installed_package['install_status'] == "ERROR" and wapt_installed_package['package'] in dict_package_app:
            if status['install'].get(wapt_installed_package['package'], False):
                print(f"Réparation de l'installation du paquet {wapt_installed_package['package']} déjà tenté")
                return_value = "ERROR"
            else:
                print(f"Tentative de réparation de l'installation du paquet {wapt_installed_package['package']}")
                if WAPT.waptserver.available():
                    status['install'][wapt_installed_package['package']] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

                    delete_key("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 'DisplayName', dict_package_app[wapt_installed_package['package']])
                    if iswin64():
                        delete_key("Software\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 'DisplayName', dict_package_app[wapt_installed_package['package']])

                    delete_key("SOFTWARE\\Classes\\Installer\\Products", 'ProductName', dict_package_app[wapt_installed_package['package']])

                    try:
                        WAPT.install(wapt_installed_package['package'])
                    except:
                        print(f"Erreur d'installation de {wapt_installed_package['package']}")
                    if return_value != "ERROR":
                        return_value = "WARNING"
                else:
                    print("Serveur WAPT non joignable - une tentative sera faite au prochain audit")

        # Si le paquet n'est pas en erreur, on le retire du json s'il existe
        elif status['install'].get(wapt_installed_package['package'], False):
            del status['install'][wapt_installed_package['package']]

        # Gestion des audit en erreur
        # Tentative d'une installation forcée
        if wapt_installed_package['last_audit_status'] == "ERROR" and wapt_installed_package['package'] != "tis-autofix-installation":
            if status['audit'].get(wapt_installed_package['package'], False):
                print(f"Réparation de l'audit du paquet {wapt_installed_package['package']} déjà tenté")
                return_value = "ERROR"
            else:
                print(f"Tentative de réparation de l'audit du paquet {wapt_installed_package['package']}")
                if WAPT.waptserver.available():
                    status['audit'][wapt_installed_package['package']] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    try:
                        WAPT.install(wapt_installed_package['package'], force=True)
                    except:
                        print(f"Erreur d'installation de {wapt_installed_package['package']}")

                    if return_value != "ERROR":
                        return_value = "WARNING"
                else:
                    print("Serveur WAPT non joignable - une tentative sera faite au prochain audit")

        # Si le paquet n'est pas en erreur, on le retire du json s'il existe
        elif status['audit'].get(wapt_installed_package['package'], False):
            del status['audit'][wapt_installed_package['package']]

    # Purge des anciennes tentative si le paquet n'est plus sur la machine
    for wapt_installed_package in status['install'].copy():
        if wapt_installed_package not in packages_installed:
            del  status['install'][wapt_installed_package]

    for wapt_installed_package in status['audit'].copy():
        if wapt_installed_package not in packages_installed:
            del status['audit'][wapt_installed_package]

    with open(json_file, 'w') as autofix:
        json.dump(status, autofix)

    return return_value

def uninstall():
    if isfile(json_file):
        remove_file(json_file)


def generate_json():
    if not isdir(r'C:\Windows\wapt'):
        mkdirs(r'C:\Windows\wapt')

    status = {}
    status['install'] = {}
    status['audit'] = {}

    with open(json_file, 'w') as autofix:
        json.dump(status, autofix)

def delete_key(uninstall, key_value, key_search):
    with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, uninstall) as key:
        i = 0
        while True:
            try:
                subkey = winreg.EnumKey(key, i)
                appkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "%s\\%s" % (uninstall, subkey))
                key_find = reg_getvalue(appkey, key_value, '')

                if re.match(f"^{key_search}$", key_find):
                    print(f'Suppression clé {uninstall}\{subkey}')
                    registry_deletekey(root=HKEY_LOCAL_MACHINE, path=uninstall, keyname=subkey, force=True, recursive=True)

                i += 1
            except WindowsError as e:
                # WindowsError: [Errno 259] No more data is available
                if e.winerror == 259:
                    break
                else:
                    raise
Mikael S
Messages : 22
Inscription : 20 janv. 2025 - 15:54

24 mars 2026 - 08:00

Une petite maj avec les dernières trouvailles.
Répondre