Un misterio de PowerShell
El otro día estaba preparando mis sesiones en la próxima Cumbre Global PowerShell + DevOps. Como suelo hacer, cuando creo demostraciones que se conectarán a máquinas remotas, suelo utilizar la computadora local como marcador de posición. Esto siempre debería funcionar, ¿verdad? Así que imagina mi sorpresa cuando este comando me dio un error:
Pero ejecutar Get-CimInstance sin el nombre de la computadora funcionó bien. Tampoco tuve problemas al usar Get-WmiObject para conectarme al host local. Lo cual es bueno porque lo primero que pensé fue en un repositorio CIM corrupto. Pero resultó ser algo más en lo que normalmente no pensamos, porque normalmente simplemente funciona.
Como Get-WmiObject funcionó y Get-CimInstance funcionó sin una conexión remota, estaba bastante seguro de que mi configuración de WMI estaba bien. Tampoco tuve problemas para consultar nada más, incluso con una conexión remota al host local. Eso dejó a WSMan como sospechoso. Cuando consulta WMI mediante los cmdlets CIM y establece una conexión remota, incluso si la computadora "remota" es el host local, PowerShell crea una conexión WSMan. Entonces mi primer paso fue recopilar un poco más de información.
Abrí el Visor de eventos y habilité el registro analítico en Registros de aplicaciones y servicios\Microsoft\Windows\Windows Remote Management. No olvide desactivarlo cuando haya terminado de solucionar el problema.
Luego volví a ejecutar mi comando.
Get-CimInstance Win32_ComputerSystem -ComputerName $env:Computername
Ahora a los registros. Revisé los eventos y vi la configuración de la red y el proceso de autenticación. Finalmente veo el comienzo de la enumeración WMI.
Después de desplazarme por algunos eventos más, encontré este error:
Interesante. WMI quiere devolver casi 3 MB de datos como respuesta. A WSMan no le gusta eso, como se confirmará en el próximo evento.
Y finalmente aparece el error XML no válido. Todo esto tiene sentido porque cuando usa WSMan, el resultado se serializa como XML y se le transmite. En mi escenario, creo que PowerShell recibió parte de la respuesta, pero luego el proceso se cancela, por lo que el XML nunca se completa y, por lo tanto, deja de ser válido.
Para finalmente verificar que WSMan era el culpable, intenté usar la utilidad winrm de línea de comando.
Claramente, mi configuración de WSMan estaba fallando, así que verifiqué mi configuración en WSMan PSDrive.
El MaxEnvelopeSizeKB era el probable culpable, así que lo mencioné.
Set-Item -Path WSMan:\localhost\maxEnvelopeSizeKB -Value 5000
Ahora volver a ejecutar mi expresión Get-CimInstance funcionó como se esperaba.
En este punto debería haber estado satisfecho, pero me preguntaba por qué obtenía tantos datos para esta clase. Volví a intentar mi comando winrm enum y, aunque no me dio un error de inmediato, tampoco me dio una respuesta de inmediato. Finalmente, el comando se completó y cuando revisé la ventana nuevamente estaba llena de valores de bytes. Afortunadamente pude desplazarme hacia arriba y ver que la propiedad OEMLogoBitmap era la responsable. Interesante.
Restablecí mi MaxEnvelopeSizeKB al valor predeterminado de 500 e intenté una consulta más selectiva usando Get-CimInstance.
Get-CimInstance Win32_ComputerSystem -ComputerName $env:Computername -Property Name,Model,TotalPhysicalMemory
Eso funcionó como se esperaba. Pero cuando intenté obtener solo la propiedad OEMLogoBitmap recibí el mismo error. Al restablecer WSMan para poder obtener todos los datos, medí el tamaño de la matriz y descubrí que solo tenía 43 KB. La serialización debe agregar algo de sobrecarga. De hecho, intenté simular el proceso.
$r = Get-CimInstance win32_computersystem -ComputerName $env:Computername
[xml]$logo = $r.OEMLogoBitmap | convertto-xml
$logo.save("c:\work\logo.xml")
Estoy seguro de que hay un poco más que esto. Aun así, terminé con un archivo de 1,8 MB de tamaño, lo cual es un problema cuando el límite predeterminado es 500 KB.
Entonces, ¿dónde me deja eso? Por ahora, no hay ningún problema en dejar mi MaxEnvelopeSizeKB en una configuración más alta. No considero nada de esto como un error. Tampoco culpo al proveedor que decidió poblar la propiedad de WMI. Por eso está ahí. Solo causa un problema al consultar la clase a través de WSMan. Cuando se utiliza una conexión DCOM, todo funciona. Debo señalar que incluso con un valor predeterminado más bajo, si hubiera sido más selectivo no habría tenido problemas.
Pero como muchos de ustedes, probablemente soy un poco vago. Aunque limitar sus consultas WMI solo a las propiedades que necesita es definitivamente una mejor práctica recomendada.