La sonda que decide si el instalador del artefacto soporta -UpdateInPlace usaba
[regex]::IsMatch, que es una llamada estatica y por tanto de lo primero que
bloquea Constrained Language Mode — el mismo motivo por el que fallo antes
(Get-Command …).Parameters en ese servidor y no en desarrollo. Habria degradado a
'desconocido' en vez de responder: no rompe, pero tampoco sirve. Pasa a
Select-String, un cmdlet puro sin resolucion de tipos.
`-ErrorAction Stop` NO es opcional, y esto lo destapo probar la ruta de FALLO con
PowerShell real, no las pruebas unitarias: Select-String emite un error NO
TERMINANTE cuando no puede leer el archivo, asi que sin el, el catch no se
dispara, -Quiet devuelve falso y un fallo de lectura se reporta como 'no' —
exactamente el defecto que esta funcion existe para eliminar.
Verificado contra PowerShell real los cuatro casos: instalador nuevo -> si,
instalador del zip 1.1.2 publicado -> no, archivo inexistente -> desconocido,
fallo de lectura -> desconocido.
Se anade probeWindowsLanguageMode y se registra SIEMPRE en el paso
precondiciones, con un aviso aparte cuando no es FullLanguage. Es el dato que
faltaba para dejar de diagnosticar a ciegas: install.ps1 todavia usa cinco
construcciones .NET que en modo restringido no funcionarian, y sin verlo en la
bitacora cada fallo raro en Windows empieza con una ronda de suposiciones.
La prueba nueva prohibe cualquier `[Tipo]::` en el script de la sonda. Se ha
caido dos veces en lo mismo; que lo impida una prueba y no la memoria.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
El panel rechazaba actualizar con 1.1.4 diciendo que su install.ps1 no declara
-UpdateInPlace. Era falso: el zip trae UpdateInPlace 8 veces y Sync-AgentTaskPath
3. El bloqueo lo causaba la sonda.
const supportsInPlace = supportsProbe.stdout.trim() === 'si';
Cualquier fallo —una excepcion, un codigo de salida distinto de cero, stdout
vacio— colapsaba a false. Mientras eso solo elegia entre -UpdateInPlace y
-Service, un falso negativo degradaba la instalacion; al convertirlo en un 409
duro paso a ser un candado permanente sobre un artefacto correcto.
Por que fallaba en ese servidor y no en la maquina donde se probo no se sabe con
certeza. El candidato mas probable es Constrained Language Mode (AppLocker/WDAC
son habituales en servidores endurecidos): restringe el acceso a propiedades de
objetos .NET como .Parameters mientras `& install.ps1` sigue funcionando, que es
justo lo que se observaba. Pero el arreglo no es adivinarlo:
- probeInstallerUpdateSupport lee el TEXTO del script y busca la declaracion
`[switch]$UpdateInPlace` con [regex]::IsMatch. No compila nada, no toca
reflexion y ninguna politica lo bloquea. Anclado a la declaracion y no a una
mencion suelta, para que un comentario no de un falso positivo.
- Tres estados en vez de dos. Solo un "no" CONFIRMADO bloquea; "desconocido"
sigue adelante con el comportamiento anterior y deja asentado POR QUE no se
pudo determinar. Un fallo de diagnostico no puede impedir el trabajo.
- El estado se decide tambien con el codigo de salida y stderr, no solo con
stdout: un execRemote que falla deja stdout vacio y eso se leia como respuesta.
Auditado el mismo patron en las otras sondas de Windows, porque dos gobiernan
fallos duros: probeWindowsAgentProcess (502 "no esta corriendo"),
probeWindowsElevation (409 por privilegios) y probeWindowsTask leian "el comando
no respondio" como "la respuesta es no". Ahora todas distinguen los dos casos.
Verificado con PowerShell real, y esta vez tambien las rutas de FALLO —que es lo
que falto la vez pasada y por lo que esto llego a produccion—: instalador nuevo
-> si, instalador del zip 1.1.2 publicado -> no, archivo inexistente ->
desconocido, y fallo de lectura -> desconocido.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>