Página 1 de 1

Enumere los paquetes y su estado

Publicado: 28 de noviembre de 2025 - 11:19 a. m.
por Mikael S
Hola,

¿existe alguna forma de listar todos los paquetes instalados en una máquina, junto con su estado y registro de auditoría, desde un archivo setup.py?

La idea sería implementar la corrección automática en ciertos casos de instalaciones problemáticas.



Saludos,

Re: Listado de paquetes y su estado

Publicado: 2 de diciembre de 2025 - 07:18
por b.ald
Buen día,

No estoy completamente seguro de lo que estás intentando hacer, pero en uno de mis paquetes tengo algo como esto:

Código: Seleccionar todo

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



Después de todo esto, ya está visible en la consola WAPT.

Comandante.

Re: Listado de paquetes y su estado

Publicado: 8 de diciembre de 2025 - 16:28
por Mikael S
Hola,

esto no me permite obtener el estado.

La idea es, por ejemplo, quiero instalar Microsoft Visual C++ 2015-2022, pero como Windows es una herramienta tan grande, la instalación MSI requiere desinstalar la anterior, pero el archivo de instalación ya se eliminó.

Por lo tanto, el instalador falla. Es imposible desinstalar, el mismo problema, así que tengo que limpiar el registro para que Windows olvide la presencia de esta instalación y así realizar una nueva.
Este tipo de situación ocurre muy a menudo con muchos productos.

Al crear un paquete de mediación, enumero todos los errores actuales y ejecuto una corrección. En este ejemplo, limpiar el registro permite una instalación exitosa.

Actualmente, tenemos esto en la consola y lo hacemos manualmente. Pero con 10,000 estaciones de trabajo que administrar, 450 de las cuales tienen errores, rápidamente se vuelve insostenible.
Tenemos de todo, desde KeePassXC, Seafile, Jabra, etc.
Algunos errores se deben a nuestra solución anterior y no aparecen en máquinas con WAPT instalado.

En resumen, la idea es gestionar todo de la forma más automática posible sin monitorizar constantemente los equipos.
Ten en cuenta que un equipo reparado no significa que el problema no vaya a reaparecer con la próxima actualización. Depende en gran medida de los instaladores (¡que suelen estar muy bien programados! :mrgreen: ).

Re: Listado de paquetes y su estado

Publicado: 8 de diciembre de 2025 - 16:34
por florentR2
Esto es muy interesante porque acabo de pasar bastante tiempo intentando encontrar una solución para el cliente Nextcloud que está produciendo bastantes errores de este tipo.
Solo arreglé este paquete con bloques try catch, pero su idea de un paquete de remediación general no es mala, me suscribiré al tema si surge una solución.
Estoy purgando esto del registro:

Código: Seleccionar todo

HKLM\SOFTWARE\\Microsoft\Windows\CurrentVersion\Uninstall\{guid}
HKLM\SOFTWARE\Classes\Installer\Products\{guid_key_wininstaller}

Re: Listado de paquetes y su estado

Publicado: 15 de diciembre de 2025 - 14:13
por b.ald
Buen día,

Por "estado", ¿se refiere a si el paquete está en "OK"/"ADVERTENCIA"/"ERROR"?

Si ese es el caso, entonces quizás puedas intentar esto:

Código: Seleccionar todo

package = WAPT.is_installed('nom_de_votre_paquet')
package_status = package['install_status']                          # recupère si status OK/WARNING/ERROR
Una simple declaración de impresión debería mostrar el estado:

Código: Seleccionar todo

print(package_status)
pero luego puedes hacer, por ejemplo, un

Código: Seleccionar todo

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



Editar: Por supuesto, el paquete en cuestión ya debe estar presente en la máquina.

Re: Listado de paquetes y su estado

Publicado: 3 de febrero de 2026 - 13:24
por Mikael S
Puede haber una forma más sencilla, pero ésta funciona para obtener una lista de paquetes cuya instalación falló.

Código: Seleccionar todo

for package in WAPT.waptdb.installed_packages_inventory():
        if package[5] == 'ERROR':
            print(package[1])
Queda por intentar corregirlo, descubriendo qué hay que corregir

Re: Listado de paquetes y su estado

Publicado: 16 de marzo de 2026 - 13:18
por Mikael S
Todavía se está probando aquí, pero este es su aspecto

Mantengo en memoria un archivo JSON con todos los paquetes que se han intentado transmitir, de modo que solo se realiza un intento.

Hasta ahora, esto está dando buenos resultados

Código: Seleccionar todo

# -*- 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)

Re: Listado de paquetes y su estado

Publicado: 16 de marzo de 2026 - 13:58
por florentR2
¡Gracias por compartir!
Mikael S escribió: 16 de marzo de 2026 - 13:18 Todavía se está probando aquí, pero este es su aspecto

Mantengo en memoria un archivo JSON con todos los paquetes que se han intentado transmitir, de modo que solo se realiza un intento.

Hasta ahora, esto está dando buenos resultados

Código: Seleccionar todo

# -*- 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

Re: Listado de paquetes y su estado

Publicado: 24 de marzo de 2026 - 08:00
por Mikael S
Una breve actualización con los últimos hallazgos.