Una ventana con tres pestanas para el mantenimiento de siempre, que no esconde ni uno solo de los comandos que ejecuta.
-------------------------------------------------------------------------------
INTRODUCCION
-------------------------------------------------------------------------------
Mantener un Windows al día son siempre los mismos tres o cuatro comandos, repartidos en dos gestores de paquetes distintos y en un par de herramientas de reparación que uno solo recuerda cuando ya hay un problema. Me canse de teclearlos y escribí una pequeña utilidad que los reúne en una ventana:
Actualizador WinGet + NPM.
No es un envoltorio que esconde lo que hace. Es justo lo contrario: ejecuta los comandos de verdad, los escribe en pantalla antes de lanzarlos y muestra su salida en vivo, tal cual la vería en una terminal. Si algún día no tengo la utilidad a mano, puedo escribir esos mismos comandos y obtener exactamente el mismo resultado. Al final del articulo los dejo todos.
-------------------------------------------------------------------------------
QUE ES
-------------------------------------------------------------------------------
Un ejecutable de unos 200 KB para Windows 10/11 de 64 bits, escrito en C# sobre .NET 8 (WinForms). No se instala: se copia y se abre con doble clic. La ventana tiene tres pestanas -WinGet, NPM y Sistema- y cada una con su propia consola negra donde aparece la salida del comando conforme se va produciendo, no al terminar.
Arriba, en la cabecera, hay tres botones que valen para toda la aplicacion:
- Detener: cancela el comando en curso cerrando el proceso y todos sus hijos.
- Reiniciar como administrador: relanza la ventana con UAC.
- Acerca de.
El titulo de la ventana avisa con un [Administrador] cuando ya se esta ejecutando elevada.
-------------------------------------------------------------------------------
PESTANA WINGET
-------------------------------------------------------------------------------
Boton: Buscar actualizaciones
Comando: winget upgrade
Boton: Ver instalados
Comando: winget list
Boton: Actualizar todo
Comando: winget upgrade --all + banderas de aceptacion
Boton: Actualizar marcados
Comando: winget upgrade --id <Id> --exact, uno por paquete
Boton: Reparar marcados
Comando: ... --uninstall-previous --force, y si falla winget install --force
Boton: Reparar todo
Comando: winget upgrade --all --include-unknown --uninstall-previous --force
Los resultados no se quedan solo en la consola: la aplicacion interpreta la tabla que devuelve winget y la vuelca en una lista con casillas, de manera que se puede actualizar unicamente lo que interesa en lugar de lanzar un --all a ciegas.
Conviene distinguir los dos listados, porque no muestran lo mismo:
- winget upgrade solo ensena los paquetes que tienen una version mas nueva disponible.
- winget list ensena el inventario completo del equipo, incluidas las aplicaciones MSIX de la Store, que ni siquiera tienen a winget como origen.
En ese listado completo la columna Disponible aparece rellena solo en los que si tienen actualizacion pendiente.
Hay ademas tres casillas:
- --include-unknown: incluye los programas cuya version instalada winget no consigue determinar.
- --silent: oculta la interfaz de los instaladores (ojo, que algunos paquetes fallan en modo silencioso).
- Volver a buscar automaticamente al terminar.
POR QUE EXISTE UN BOTON "REPARAR"
Este es el motivo real por el que acabe escribiendo la utilidad. Tarde o temprano, winget upgrade --all deja algún paquete atrás con un error parecido a que no encuentra el instalador de la version que ya está instalada. La razon es que, para ciertos paquetes, winget necesita desinstalar la version anterior antes de poner la nueva, y para desinstalarla busca el instalador original en su cache. Si esa cache se limpió, o el paquete se instaló de otra forma, ahi se queda atascado.
La salida es --uninstall-previous, que le indica a winget que desinstale la version anterior usando la información del propio manifiesto en lugar del instalador cacheado, acompañado de --force para que continúe ante problemas no relacionados con la seguridad. Si ni con esas, "Reparar marcados" da un segundo paso: reinstalar el paquete desde cero con winget install --force, que se descarga el instalador nuevo completo.
-------------------------------------------------------------------------------
PESTANA NPM
-------------------------------------------------------------------------------
Boton: Listar globales
Comando: npm ls -g --depth=0
Boton: Ver desactualizados
Comando: npm outdated -g
Boton: Actualizar globales
Comando: npm update -g
Un detalle de npm outdated: devuelve código de salida 1 cuando encuentra paquetes pendientes. Eso, para cualquier script, significa "ha fallado". La aplicación lo trata como lo que es, información, y no lo pinta como error.
EL DESCONCIERTO DE "NO HAY NADA QUE ACTUALIZAR" SEGUIDO DE 685 PAQUETES
CAMBIADOS
Esto me paso usando la propia utilidad y merece su apartado, porque es una de esas cosas que parecen un fallo y no lo son. La secuencia fue: npm outdated -g no devolvió ni una línea, señal de que todo estaba al dia. Acto seguido, npm update -g respondió esto:
> npm outdated -g
-- fin en 2,5 s, codigo 0 --
> npm update -g
npm warn deprecated inflight@1.0.6 ...
npm warn deprecated rimraf@2.4.5 ...
changed 685 packages in 2m
No hay contradicción: los dos comandos miran cosas distintas. npm outdated, por omisión, solo compara las dependencias de primer nivel, que en el ámbito global son exactamente los paquetes que salen en npm ls -g --depth=0. En mi caso eran cinco, y los cinco estaban en su última version. De ahi la salida vacía.
npm update, en cambio, recorre el arbol entero y sube cada dependencia transitiva a la version más nueva que permita el rango semver de su padre. Un paquete como eas-cli arrastra el solo varios cientos de dependencias anidadas, y ahi si había versiones nuevas. El número que informa al final, además, no son 685 actualizaciones: changed N packages cuenta los paquetes añadidos, eliminados y modificados al recalcular el arbol, y una reorganización de dependencias infla bastante esa cifra.
Para ver lo que update va a tocar de verdad hay que pedirle a outdated que mire también lo anidado:
npm outdated -g --all
En mi equipo, ese comando seguía devolviendo 404 paquetes desactualizados justo después de actualizar. Al mirarlos uno por uno, todos tenían la columna Wanted igual a Latest y por encima de Current: son saltos de version mayor (Babel 7 a 8, Expo 55 a 57) que el rango declarado por el paquete padre no admite. npm update respeta semver y nunca cruza un mayor por su cuenta; eso solo se arregla cuando el autor del paquete de arriba publica una version nueva. Y de ahi vienen también los avisos de deprecated que reaparecen en cada actualización: son dependencias viejas clavadas dentro de cadenas ajenas, no algo que uno haya instalado.
-------------------------------------------------------------------------------
PESTANA SISTEMA (DISM . SFC)
-------------------------------------------------------------------------------
Boton: 1. Comprobar
Comando: DISM /Online /Cleanup-Image /CheckHealth
Boton: 2. Analizar
Comando: DISM /Online /Cleanup-Image /ScanHealth
Boton: 3. Reparar
Comando: DISM /Online /Cleanup-Image /RestoreHealth
Boton: 4. Archivos de sistema
Comando: sfc /scannow
Boton: Secuencia completa
Comando: Los cuatro anteriores, en ese orden
El orden no es capricho. SFC repara los archivos del sistema tomándolos del almacén de componentes, así que lo sensato es que DISM haya dejado sano ese almacén antes de lanzar SFC; al revés, SFC puede estar copiando archivos de un origen que también esta dañado. Y RestoreHealth descarga los archivos correctos desde Windows Update, de modo que necesita conexión a internet.
Los cuatro exigen permisos de administrador. Si la ventana no está elevada, aparece un aviso que ofrece reiniciarla con UAC, ejecutar de todos modos -fallara con el error 740- o cancelar. Como ScanHealth, RestoreHealth y sfc /scannow tardan varios minutos, la barra de estado va mostrando el tiempo transcurrido para saber que aquello sigue vivo.
Codigos de salida que conviene reconocer:
0 correcto
740 faltan permisos de administrador
3010 correcto pero hay que reiniciar
El detalle completo queda, como siempre, en:
%WinDir%\Logs\CBS\CBS.log para SFC
%WinDir%\Logs\DISM\dism.log para DISM
-------------------------------------------------------------------------------
LOS MISMOS COMANDOS, A MANO
-------------------------------------------------------------------------------
La utilidad no hace nada que no se pueda hacer en una terminal, y ese fue un requisito desde el principio. Cada vez que se pulsa un botón, la consola escribe primero la línea completa del comando -en azul- y después su salida. Asi que siempre se puede leer que se ejecutó, copiarlo y repetirlo a mano.
SI QUIERES USAR LA APLICACIÓN LA PUEDES DESCARGAR AQUÍ
Aqui está el repertorio completo, por si alguien quiere quedarse solo con esta parte del artículo:
# --- WinGet -------------------------------------------------
winget upgrade # lo que tiene version mas nueva
winget list # inventario completo del equipo
winget upgrade --all --include-unknown --accept-package-agreements --accept-source-agreements
# un paquete concreto (el Id sale en la segunda columna del listado)
winget upgrade --id Microsoft.PowerShell --exact --accept-package-agreements --accept-source-agreements
# reparacion: desinstalar la version previa antes de instalar la nueva
winget upgrade --id <Id> --exact --uninstall-previous --force --accept-package-agreements --accept-source-agreements
winget install --id <Id> --exact --force --accept-package-agreements --accept-source-agreements
# --- NPM global ---------------------------------------------
npm ls -g --depth=0 # que tengo instalado
npm outdated -g # desactualizados de primer nivel
npm outdated -g --all # incluyendo dependencias anidadas
npm update -g # actualizar respetando semver
# --- Sistema (consola COMO ADMINISTRADOR) -------------------
DISM /Online /Cleanup-Image /CheckHealth
DISM /Online /Cleanup-Image /ScanHealth
DISM /Online /Cleanup-Image /RestoreHealth
sfc /scannow
-------------------------------------------------------------------------------
DOS DETALLES DE IMPLEMENTACION
-------------------------------------------------------------------------------
Aprovecho para dejar constancia de lo que más trabajo dio, que no fue la interfaz sino leer bien la salida de los programas.
1. Cada herramienta escribe en una codificación distinta. winget y npm usan UTF-8, sfc.exe escribe en UTF-16LE y dism.exe lo hace en la página de códigos OEM de la consola (850, 437... según el idioma de Windows). Si se decodifica todo como UTF-8, los acentos salen corruptos y, en el caso de SFC, directamente no se ve nada: la consola aparece vacía y uno cree que el comando no arranco.
2. Las barras de progreso no son texto normal. Estas herramientas se reescriben la linea a base de retornos de carro y codigos de color ANSI. Hay que limpiar esas secuencias para que la salida se lea igual que en una terminal. Y cuidado con sfc.exe, que termina sus lineas con \r\r\n: si se interpreta cada retorno de carro como "reescribe la linea anterior", el resultado es una consola en blanco.
-------------------------------------------------------------------------------
REQUISITOS
-------------------------------------------------------------------------------
- Windows 10 u 11 de 64 bits.
- .NET 8 Desktop Runtime, para la version pequena de ~200 KB. Tambien se puede
compilar autonoma, de unos 150 MB, que no necesita nada instalado.
- winget (viene con el Instalador de aplicaciones) y Node.js, según la pestana
que se use.
Nada más. Es una herramienta pequeña y deliberadamente aburrida: su gracia esta en que no oculta nada de lo que hace por debajo.

