Page 2 sur 2

Re: Lister les paquets et leur état

Publié : 09 oct. 2026 - 14:42
par Mikael S
Bonjour,

Une petite maj depuis tout ce temps. Nous avons de très bons résultats depuis

Code : Tout sélectionner

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

from setuphelpers import *

# Dictionnaire package wapt => nom de l'application en format regex
dict_package_app = {
    "tis-adobereader" : r"Adobe Acrobat \(64-bit\)",
    "tis-affinity" : "Affinity",
    "tis-affinity-designer" : "Affinity Designer",
    "tis-affinity-photo" : "Affinity Photo",
    "tis-affinity-publisher" : "Affinity Publisher",
    "tis-affinity-designer-2" : "Affinity Designer 2",
    "tis-affinity-photo-2" : "Affinity Photo 2",
    "tis-affinity-publisher-2" : "Affinity Publisher 2",
    "tis-anaconda3": "Anaconda3 [0-9].*",
    "tis-audacity" : "Audacity [0-9.]+",
    "tis-bcu-bios-hp": "HP BIOS Configuration Utility",
    "tis-beyondtrust-rs" : "BeyondTrust Jump Client - pmad.unistra.fr",
    "tis-calculator" : r"C:\\Program Files\\WindowsApps\\Microsoft\.WindowsCalculator.*",
    "tis-cartes" : r"C:\\Program Files\\WindowsApps\\Microsoft\.WindowsMaps_.*",
    "tis-chrome" : "Google Chrome",
    "tis-disable-telemetry" : "Microsoft Update Health Tools",
    "tis-element" : "Element",
    "tis-extensions-de-support-web" : r"C:\\Program Files\\WindowsApps\\Microsoft\.WebMediaExtensions_.*",
    "tis-firefox" : r"Mozilla Firefox \(x(86|64) [a-zA-Z -]+\)",
    "tis-firefox-esr" : r"Mozilla Firefox ESR \(x(86|64) [a-zA-Z -]+\)",
    "tis-forticlient-vpn" : "FortiClient VPN",
    "tis-foxit-pdfeditor-11" : "Foxit PDF Editor",
    "tis-foxit-pdfeditor-12" : "Foxit PDF Editor",
    "tis-foxit-pdfeditor-13" : "Foxit PDF Editor",
    "tis-foxit-pdfeditor-14" : "Foxit PDF Editor",
    "tis-foxit-pdfeditor-2024" : "Foxit PDF Editor",
    "tis-gimp" : "GIMP [0-9-.]+",
    "tis-googleearth" : "Google Earth Pro",
    "tis-glpi-agent" : "GLPI Agent [0-9.]+",
    "tis-keepassxc" : "KeePassXC",
    "tis-libreoffice-fresh" : "LibreOffice [0-9.]+",
    "tis-microsoft-windowsalarms" : r"C:\\Program Files\\WindowsApps\\Microsoft\.WindowsAlarms.*",
    "tis-microsoft-edge" : "Microsoft Edge(| Update)",
    "tis-microsoft-photos" : r"C:\\Program Files\\WindowsApps\\Microsoft\.Windows\.Photos.*",
    "tis-microsoft-soundrecorder" : r"C:\\Program Files\\WindowsApps\\Microsoft\.WindowsSoundRecorder.*",
    "tis-microsoft-stickynotes" : r"C:\\Program Files\\WindowsApps\\\Microsoft\.MicrosoftStickyNotes.*",
    "tis-microsoft-teams" : "Teams Machine-Wide Installer",
    "tis-microsoft-windows-camera"  : r"C:\\Program Files\\WindowsApps\\Microsoft\.WindowsCamera.*",
    "tis-naps2" : "NAPS2",
    "tis-windows-notepad" : r"C:\\Program Files\\WindowsApps\\Microsoft\.WindowsNotepad.*",
    "tis-onlyoffice-desktop" : r"ONLYOFFICE [0-9.]+ \(x64\)",
    "tis-oracle-java8-jre-free" : "Java 8 Update [0-9]+(| x64 bit)",
    "tis-paint.net" : "(paint.net|Paint.NET)",
    "tis-paint-3d" : r"C:\\Program Files\\WindowsApps\\Microsoft\.MSPaint.*",
    "tis-pdf24-creator" : "PDF24 Creator",
    "tis-putty" : r"PuTTY release [0-9.]+( \(64-bit\)|)",
    "tis-rtools" : "Rtools [0-9 ().-]+",
    "tis-seafile" : "Seafile [0-9.]+",
    "tis-sphinx-iq3" : "SphinxIQ3",
    "tis-spyder" : "Spyder [0-9]",
    "tis-stormshield-vpn" : "Stormshield SSL VPN Client",
    "tis-teamviewer" : "TeamViewer( [0-9]+|)",
    "tis-thunderbird" : "Mozilla Thunderbird .*",
    "tis-vcredist2015-2022" : r"Microsoft Visual C\+\+ (2015-(2019|2022) Redistributable \(x(86|64)\)|(2019|2022) X(86|64) (Additional|Minimum) Runtime) - [0-9.]+",
    "tis-wazo" : "Wazo Desktop",
    "tis-webex" : "(Webex|Cisco Webex Meetings)",
    "tis-webview2" : "Microsoft Edge WebView2 Runtime",
    "tis-withsecure" : "WithSecure™ Client Security Premium",
    "tis-zoom" : r"Zoom Workplace \(64-bit\)"
}

# Liste des appx gérées
appx = [
    "tis-calculator",
    "tis-cartes",
    "tis-extensions-de-support-web",
    "tis-microsoft-windowsalarms",
    "tis-paint-3d",
    "tis-microsoft-photos",
    "tis-microsoft-soundrecorder",
    "tis-microsoft-stickynotes",
    "tis-microsoft-windows-camera",
    "tis-windows-notepad"
]

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\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 'DisplayName', dict_package_app[wapt_installed_package['package']], winreg.KEY_WOW64_32KEY)
                    delete_key("SOFTWARE\\Classes\\Installer\\Products", 'ProductName', dict_package_app[wapt_installed_package['package']])
                    delete_key("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Appx\\AppxAllUserStore\\Applications", 'Path', dict_package_app[wapt_installed_package['package']])

                    try:
                        WAPT.install(wapt_installed_package['package'], force=True)
                    except:
                        print(f"Erreur d'installation de {wapt_installed_package['package']}")
                        if not status['wmi'] and WAPT.is_installed("tis-script-cache-wmi-reparer") and wapt_installed_package['package'] in appx:
                            print('Tentative de réparation du cache wmi')
                            WAPT.install("tis-script-cache-wmi-reparer", force=True)
                            status['wmi'] = True
                            print('Une tentative sera faite au prochain audit')
                            del status['install'][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) and wapt_installed_package['install_status'] == "OK":
            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'] not in ("tis-audit-battery", "tis-autofix-installation", "tis-pending-reboot-notification"):
            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]

    # Réinitialisation du status wmi si plus aucune appx problématique
    appx_en_erreur = False
    if any(package in appx for package in status['install']):
        appx_en_erreur = True

    if not appx_en_erreur:
        status['wmi'] = False

    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'] = {}
    status['wmi'] = False

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

def delete_key(key_uninstall, key_value, key_search, access=winreg.KEY_WOW64_64KEY):
    for subkey in subkeys(key_uninstall, access):
        appkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, rf"{key_uninstall}\{subkey}", 0, winreg.KEY_READ | access)

        key_find = reg_getvalue(appkey, key_value, '')

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

def subkeys(path, access=winreg.KEY_WOW64_64KEY, hkey=HKEY_LOCAL_MACHINE,):
    with suppress(WindowsError), winreg.OpenKey(hkey, path, 0, winreg.KEY_READ | access) as k:
        for i in itertools.count():
            yield winreg.EnumKey(k, i)
Pour les appx, un secour est parfois utile lorsque le cache wmi est corrompu, mais dans la réalité, c'est peu utilisé.
Il existe une fonction dans wapt pour restaurer le cache mais qui remonte juste une erreur.
Voici un code qui marche

Code : Tout sélectionner

# -*- coding: utf-8 -*-
from setuphelpers import *
import glob
import time


def install():
    if force:
        # https://woshub.com/wmi-troubleshooting/
        # arret des services associé à winmgmt
        set_service_start_mode("winmgmt", "Disabled")

        if service_installed('winmgmt') and service_is_running ('winmgmt'):
            run('cmd /c net stop winmgmt /y')

        print('Commande : winmgmt /resetrepository')
        run('cmd /C winmgmt /resetrepository')

        print('Commande : winmgmt /resyncperf')
        run('cmd /C winmgmt /resyncperf')

        print(r'Commande : regsvr32 /s %systemroot%\system32\scecli.dll')
        run(r'cmd /C regsvr32 /s %systemroot%\system32\scecli.dll')

        print(r'Commande : regsvr32 /s %systemroot%\system32\userenv.dll')
        run(r'cmd /C regsvr32 /s %systemroot%\system32\userenv.dll')

        for file in glob.glob(r'c:\windows\system32\wbem\*.dll'):
            print(rf'Commande : regsvr32 /s {file}')
            run_notfatal(rf'cmd "/C regsvr32 /s {file}"')

        for file in glob.glob(r'c:\windows\system32\wbem\*.mof'):
            if "uninstall" not in file.lower():
                print(rf'Commande : mofcomp {file}')
                run_notfatal(rf'cmd "/C mofcomp {file}"')

        for file in glob.glob(r'c:\windows\system32\wbem\*.mfl'):
            if "uninstall" not in file.lower():
                print(rf'Commande : mofcomp {file}')
                run_notfatal(rf'cmd "/C mofcomp {file}"')

        if service_installed('winmgmt') and not service_is_running ('winmgmt'):
            print('Relance du service winmgmt')
            service_start('winmgmt')

        set_service_start_mode("winmgmt", "Auto")

        print('Commande : wmiprvse /regserver')
        run('cmd /C wmiprvse /regserver')

        print(r'Commande : gpupdate /force /target:computer"')
        run(r'gpupdate /force /target:computer"')

def audit():
    winmgmt = run('winmgmt /verifyrepository')

    print(winmgmt)

    if "WMI EST cohérent" in winmgmt:
        retour = "OK"
    elif "WMI repository is consistent" in winmgmt:
        retour = "OK"
    else:
        retour = "ERROR"

    try:
        get_powershell_str('get-printer')
        get_powershell_str('Get-BitLockerVolume -MountPoint c:')
        get_powershell_str('Get-AppXProvisionedPackage -Online')
    except:
        print('Erreur WMI détectée')
        retour = "ERROR"

    return retour