Error: Paquete de actualización (1603)

Preguntas sobre paquetes WAPT / Solicitudes y ayuda sobre paquetes WAPT.
Reglas del foro
Reglas del foro de la comunidad
* Soporte en inglés en www.reddit.com/r/wapt
* El soporte de la comunidad en francés está disponible en este foro
* Por favor, anteponga [RESUELTO] al título del tema si está resuelto.
* Por favor, no edite un tema que esté etiquetado como [RESUELTO]. Abra un nuevo tema haciendo referencia al anterior.
* Especifique la versión de WAPT instalada, la versión completa y el número de compilación (2.2.1.11957 / 2.2.2.12337 / etc.), así como la edición Enterprise/Discovery.
* Las versiones 1.8.2 y anteriores ya no son compatibles. Las únicas preguntas aceptadas sobre la versión 1.8.2 están relacionadas con la actualización a una versión compatible (2.1, 2.2, etc.).
* Especifique el sistema operativo del servidor (Linux/Windows) y la versión (Debian Buster/Bullseye - CentOS 7 - Windows Server 2012/2016/2019).
* Especifique el sistema operativo de la máquina de administración/creación de paquetes y de la máquina con el agente problemático, si corresponde (Windows 7/10/11/Debian 11/etc.).
* Evite hacer varias preguntas al abrir un tema, ya que podría ser ignorado. Si hay varios temas, ábralos por separado, preferiblemente uno tras otro y no todos a la vez (es decir, no sature el foro con spam).
* Incluya fragmentos de código, capturas de pantalla y otras imágenes directamente en la publicación. Los enlaces a Pastebin, Bitly y otros sitios de terceros serán eliminados sistemáticamente.
* Como en cualquier foro comunitario, el soporte es proporcionado voluntariamente por los miembros. Si necesita soporte comercial, puede comunicarse con el departamento de ventas de Tranquil IT al 02.40.97.57.55.
ddcorazon
Mensajes: 37
Inscripciones: 30 de mayo de 2023 - 23:53 horas.

20 de agosto de 2025 - 00:41

(siguiente)

Una vez terminado, si todo ha ido bien, lo veremos en la auditoría browser-msi-after-fix
Captura de pantalla 2025-08-20 001828.png
Captura de pantalla 2025-08-20 001828.png (42,03 KB) Vista 11558 veces
Y normalmente una vez terminado logro hacer mis actualizaciones desde Wapt
Captura de pantalla 2025-08-20 003943.png
Captura de pantalla 2025-08-20 003943.png (58,23 KB) Vista 11558 veces
Tengo algunas máquinas en las que no funcionó (tampoco funciona directamente en las máquinas, incluso con el MSI correcto de la versión correcta)

A continuación se muestra el código (puede que esté más optimizado, lo admito)😅)

Código: Seleccionar todo

#Auteur ddcorazon
# -*- coding: utf-8 -*-
from setuphelpers import *
import os, glob, shutil, traceback

# === CONFIG ===
tools = ["chrome", "edge"]
AUDIT_SCOPE_BEFORE = "browser-msi"
AUDIT_SCOPE_AFTER  = "browser-msi-after-fix"

_UNINSTALL_KEYS = [
    r'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
    r'HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall',
    r'HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
    r'HKCU\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall',
]

def install():
    """Copie le dossier 'msi' du paquet vers persistent_dir\\msi pour l'audit."""
    src_dir = makepath(os.getcwd(), "msi")  # côté build/exec, cwd = racine du paquet
    dst_dir = makepath(persistent_dir, "msi")
    if os.path.isdir(src_dir):
        print("[INSTALL] Sync MSIs ->", dst_dir)
        if os.path.isdir(dst_dir):
            shutil.rmtree(dst_dir, ignore_errors=True)
        shutil.copytree(src_dir, dst_dir)
    else:
        print("[INSTALL] Aucun dossier 'msi' à copier (", src_dir, ")")

def uninstall():
    pass

# ----------------- Helpers -----------------
def _normalize_tools(t):
    if isinstance(t, (list, tuple)):
        lst = [str(x).strip() for x in t]
    else:
        lst = [s.strip() for s in str(t).split(",")]
    return [s.lower() for s in lst if s]

def _scan_registry(term):
    """Retourne (DisplayName, LocalPackagePath, DisplayVersion)."""
    for base in _UNINSTALL_KEYS:
        try:
            for sub in glob.glob(base + r'\*'):
                try:
                    dn = registry_readstring(sub, 'DisplayName', '')
                    if not dn or term not in dn.lower():
                        continue
                    lp = registry_readstring(sub, 'LocalPackage', '')
                    dv = registry_readstring(sub, 'DisplayVersion', '')
                    return ((dn or '').strip(), (lp or '').strip(), (dv or '').strip())
                except Exception:
                    continue
        except Exception:
            continue
    return (None, None, None)

def _scan_wmi(term):
    """Fallback WMI (Win32_Product)."""
    try:
        ps = (
            r"Get-WmiObject -Class Win32_Product | "
            r"Where-Object { $_.Name -ne $null -and $_.Name -like '*" + term + r"*' } | "
            r"Select-Object Name, LocalPackage, Version"
        )
        data = run_powershell(ps)
        if not data:
            return (None, None, None)
        row = data[0] if isinstance(data, list) else data
        name  = (row.get('Name') or '').strip()
        local = (row.get('LocalPackage') or '').strip()
        ver   = (row.get('Version') or '').strip()
        return (name or None, local or None, ver or None)
    except Exception:
        return (None, None, None)

def _detect_one(term):
    """Retourne (name, pkg_basename, version, file_flag)."""
    name, local, ver = _scan_registry(term)
    if not name and not local and not ver:
        name, local, ver = _scan_wmi(term)

    pkg = os.path.basename(local) if local else ""
    file_flag = "Unknown"
    if pkg:
        installer_dir = os.path.join(os.environ.get("SystemRoot", r"C:\Windows"), "Installer")
        candidate1 = os.path.join(installer_dir, pkg)
        candidate2 = local
        if (candidate2 and os.path.exists(candidate2)) or os.path.exists(candidate1):
            file_flag = "Found"
        else:
            file_flag = "Missing"

    return name or "", pkg, ver or "", file_flag

def _run_audit(scope):
    """Exécute l’audit pour tous les tools, retourne (result_data, found_any)."""
    result_data = {}
    found_any = False

    for term in _normalize_tools(tools):
        section = term.capitalize()
        name, pkg, ver, file_flag = _detect_one(term)

        result_data[section] = {
            "Name": name,
            "Package": pkg,
            "Version": ver,
            "File": file_flag
        }
        if name or pkg or ver:
            found_any = True

    WAPT.write_audit_data_if_changed(scope, "audit_data", result_data)
    WAPT.write_audit_data_if_changed(scope, "result", "OK" if found_any else "NotFound")
    return result_data, found_any

def _fix_missing(result_data):
    """
    Copie les MSI manquants depuis persistent_dir\\msi\\<tool>-<version>.msi
    -> C:\\Windows\\Installer\\<package>
    """
    installer_dir = os.path.join(os.environ.get("SystemRoot", r"C:\Windows"), "Installer")
    src_dir = makepath(persistent_dir, "msi")
    print(f"[INFO] Dossier source MSI: {src_dir}")

    for app, info in result_data.items():
        tool = app.lower()
        pkg  = info.get("Package")   # ex: 16af95e8.msi
        ver  = info.get("Version")   # ex: 139.0.x.x
        flag = info.get("File")

        if flag == "Missing" and pkg and ver:
            src = makepath(src_dir, f"{tool}-{ver}.msi")
            dst = makepath(installer_dir, pkg)
            if os.path.exists(src):
                print(f"[FIX] Copie {src} -> {dst}")
                os.makedirs(installer_dir, exist_ok=True)
                shutil.copyfile(src, dst)
            else:
                print(f"[WARN] MSI source introuvable pour {app}: {src}")

def _cleanup_persistent_msis():
    """Supprime persistent_dir\\msi pour ne rien laisser sur le poste."""
    msi_dir = makepath(persistent_dir, "msi")
    if os.path.isdir(msi_dir):
        print(f"[CLEANUP] Suppression du répertoire: {msi_dir}")
        shutil.rmtree(msi_dir, ignore_errors=True)

# ----------------- Audit principal -----------------
def audit():
    try:
        # 1) Audit avant
        before_data, found_any = _run_audit(AUDIT_SCOPE_BEFORE)

        # 2) Corrections si nécessaires
        if found_any:
            needs_fix = any(info.get("File") == "Missing" for info in before_data.values())
            if needs_fix:
                _fix_missing(before_data)
                # 3) Audit après correction
                _run_audit(AUDIT_SCOPE_AFTER)
            return "OK"
        else:
            return "NotFound"

    except Exception as e:
        print("[ERROR] Exception durant l'audit :", e)
        print(traceback.format_exc())
        return "ERROR"

    finally:
        # 4) Toujours nettoyer le persistent_dir\msi en fin d’audit
        _cleanup_persistent_msis()
 
ddcorazon
Mensajes: 37
Inscripciones: 30 de mayo de 2023 - 23:53 horas.

3 de septiembre de 2025 - 15:30

Hola a todos,

Dada la casi imposibilidad de encontrar archivos MSI antiguos de Chrome Enterprise, opté por otra solución (que por cierto funciona para Edge y "cualquier otro MSI")
Es una solución bastante drástica, pero si no tenemos otra opción, la idea es usar una antigua utilidad de Microsoft llamada msizap. Al recuperar el identificador del MSI instalado, podemos eliminar del registro todas las referencias a ese MSI. Así, por ejemplo, Chrome o Edge ya no aparecerán como instalados en el Panel de Control, aunque todavía lo estén.
Así que aquí recuperamos el identificador
Obtener-WmiObject Win32_Product | Donde-Objeto { $_.Nombre -like "*chrome*" } | Seleccionar-Nombre, Versión, Número de Identificación del Objeto

Nombre Versión Número de identificación
---- ------- -----------------
Google Chrome 139.0.7258.155 {AC157B81-B63F-3C87-802D-6A050E1EFBE7}

Luego, usando MSIzap.exe T {el identificador que recuperamos}

Una vez hecho esto, Windows consideró que Chrome no estaba instalado, así que forzamos la instalación desde WAPT y realizó una instalación limpia. Una vez corregido el problema, pude completar la actualización sin problemas.

A continuación se muestra el código (se puede optimizar; todavía hay algunas cosas que no se utilizan, dadas las muchas cosas que he probado)

Código: Seleccionar todo

# -*- coding: utf-8 -*-
from setuphelpers import *
import os, glob, shutil, traceback

# === CONFIG ===
tools = ["chrome"]
AUDIT_SCOPE_BEFORE = "chrome-msi"
AUDIT_SCOPE_AFTER  = "chrome-msi-after-fix"

_UNINSTALL_KEYS = [
    r'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
    r'HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall',
    r'HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
    r'HKCU\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall',
]

def install():
    """Copie msizap.exe dans persistent_dir\\msi pour utilisation locale."""
    src_dir = makepath(os.getcwd(), "msi")  # côté paquet WAPT
    dst_dir = makepath(persistent_dir, "msi")
    if os.path.isdir(src_dir):
        print("[INSTALL] Sync MSIs ->", dst_dir)
        if os.path.isdir(dst_dir):
            shutil.rmtree(dst_dir, ignore_errors=True)
        shutil.copytree(src_dir, dst_dir)
    else:
        print("[INSTALL] Aucun dossier 'msi' à copier (", src_dir, ")")

def uninstall():
    pass

# ----------------- Helpers -----------------
def _normalize_tools(t):
    if isinstance(t, (list, tuple)):
        lst = [str(x).strip() for x in t]
    else:
        lst = [s.strip() for s in str(t).split(",")]
    return [s.lower() for s in lst if s]

def _scan_registry(term):
    """Retourne (DisplayName, LocalPackagePath, DisplayVersion)."""
    for base in _UNINSTALL_KEYS:
        try:
            for sub in glob.glob(base + r'\*'):
                try:
                    dn = registry_readstring(sub, 'DisplayName', '')
                    if not dn or term not in dn.lower():
                        continue
                    lp = registry_readstring(sub, 'LocalPackage', '')
                    dv = registry_readstring(sub, 'DisplayVersion', '')
                    return ((dn or '').strip(), (lp or '').strip(), (dv or '').strip())
                except Exception:
                    continue
        except Exception:
            continue
    return (None, None, None)

def _scan_wmi(term):
    """Retourne (Name, LocalPackage, Version, IdentifyingNumber)."""
    try:
        ps = (
            r"Get-WmiObject -Class Win32_Product | "
            r"Where-Object { $_.Name -ne $null -and $_.Name -like '*" + term + r"*' } | "
            r"Select-Object Name, LocalPackage, Version, IdentifyingNumber"
        )
        data = run_powershell(ps)
        if not data:
            return (None, None, None, None)
        row = data[0] if isinstance(data, list) else data
        name  = (row.get('Name') or '').strip()
        local = (row.get('LocalPackage') or '').strip()
        ver   = (row.get('Version') or '').strip()
        prod  = (row.get('IdentifyingNumber') or '').strip()
        return (name or None, local or None, ver or None, prod or None)
    except Exception:
        return (None, None, None, None)

def _detect_one(term):
    """Retourne (name, pkg_basename, version, file_flag, product_id)."""
    name, local, ver = _scan_registry(term)
    prod_id = ""
    if not name and not local and not ver:
        name, local, ver, prod_id = _scan_wmi(term)
    else:
        # récupère aussi via WMI pour ProductCode
        _, _, _, prod_id = _scan_wmi(term)

    pkg = os.path.basename(local) if local else ""
    file_flag = "Unknown"
    if pkg:
        installer_dir = os.path.join(os.environ.get("SystemRoot", r"C:\Windows"), "Installer")
        candidate1 = os.path.join(installer_dir, pkg)
        candidate2 = local
        if (candidate2 and os.path.exists(candidate2)) or os.path.exists(candidate1):
            file_flag = "Found"
        else:
            file_flag = "Missing"

    return name or "", pkg, ver or "", file_flag, prod_id

def _run_audit(scope):
    """Exécute l’audit pour Chrome, retourne (result_data, found_any)."""
    result_data = {}
    found_any = False

    for term in _normalize_tools(tools):
        section = term.capitalize()
        name, pkg, ver, file_flag, prod_id = _detect_one(term)

        result_data[section] = {
            "Name": name,
            "Package": pkg,
            "Version": ver,
            "File": file_flag,
            "Id": prod_id
        }
        if name or pkg or ver:
            found_any = True

    WAPT.write_audit_data_if_changed(scope, "audit_data", result_data)
    WAPT.write_audit_data_if_changed(scope, "result", "OK" if found_any else "NotFound")
    return result_data, found_any

def _zap_chrome(result_data):
    """Exécute msizap.exe T {GUID} pour Chrome trouvé."""
    zap_exe = makepath(persistent_dir, "msi", "msizap.exe")
    if not os.path.exists(zap_exe):
        print(f"[ERROR] msizap.exe introuvable : {zap_exe}")
        return

    for app, info in result_data.items():
        prod_id = info.get("Id") or ""
        if prod_id and prod_id.startswith("{"):
            cmd = f'"{zap_exe}" T {prod_id}'
            print(f"[ZAP] {cmd}")
            run(cmd)

def _cleanup_persistent_msis():
    """Supprime persistent_dir\\msi après utilisation."""
    msi_dir = makepath(persistent_dir, "msi")
    if os.path.isdir(msi_dir):
        print(f"[CLEANUP] Suppression du répertoire: {msi_dir}")
        shutil.rmtree(msi_dir, ignore_errors=True)

# ----------------- Audit principal -----------------
def audit():
    try:
        # 1) Audit avant
        before_data, found_any = _run_audit(AUDIT_SCOPE_BEFORE)

        # 2) Si Chrome trouvé, zapper avec msizap
        if found_any:
            _zap_chrome(before_data)

        # 3) Audit après
        _run_audit(AUDIT_SCOPE_AFTER)
        return "OK" if found_any else "NotFound"

    except Exception as e:
        print("[ERROR] Exception durant l'audit :", e)
        print(traceback.format_exc())
        return "ERROR"

    finally:
        # 4) Nettoyage final
        _cleanup_persistent_msis()

Aquí lo tienes, por si te sirve de algo. 🙃
Respuesta