
¿Por qué se Invoke-Command
obtienen resultados diferentes cuando los comandos se ejecutan de forma remota que cuando exactamente los mismos comandos se ejecutan localmente en exactamente el mismo sistema?
Estos comandos invocados remotamente muestran 4 líneas vacías:
PS > Invoke-Command cluster02 { cmd /c dir c:\ | select-string 'bytes free' }
Si bien estos comandos locales generan el resultado esperado:
PS > Invoke-Command cluster02 { cmd /c dir c:\ | select-string 'bytes free' }
11 Dir(s) 828,179,570,688 bytes free
Si primero inicio Enter-PSSession cluster02
y luego los ejecuto, ambos comandos devuelven el resultado esperado.
¿Es un error en este antiguo PowerShell (Windows 2012) o me pierdo alguna peculiaridad de PS? Si es un error o una peculiaridad, ¿cuándo se manifiesta? En otras palabras, ¿hay algo que aprender de este extraño comportamiento?
Respuesta1
El problema que tienes es que estás intentando ejecutar de forma remota cmd /c
con un comando cmd dir
y luego canalizarlo a un comando de PowerShell de forma remota.
Si bien espera que esto funcione exactamente de la misma manera que lo hace localmente cuando lo ejecuta de forma remota, se sabe que esto tiene diferencias y causa confusión.
Como se indica en elLos comandos que necesitan un perfil de usuario pueden fallar cuando se ejecutan de forma remotacorreo
El problema es que, cuando te conectas a una computadora remota, no estás creando un entorno de usuario completo. Técnicamente no estás “iniciando sesión” en la máquina en el sentido habitual. Te estás autenticando, sí, pero de la misma manera que te autenticarías en una carpeta compartida. Su conexión remota no tiene un perfil de usuario completo, por lo que cualquier cosa que se espere puede generar errores y fallar (incluso si no muestran esos errores).
Desafortunadamente, no hay una solución fácil para esto.
Cuando ejecuto Invoke-Command -ScriptBlock {}
en una máquina remota, trato de mantener los comandos en PowerShell lo más posible. Debe realizar pruebas exhaustivas si está combinando cmd y PowerShell, ya que es posible que no funcione de la misma manera que cuando lo ejecuta mientras está conectado al sistema de forma interactiva.
PowerShell remoto, obtenga espacio libre en el disco en bytes (no cmd
)
Invoke-Command -ComputerName Cluster02 -ScriptBlock {(Get-PSDrive C).Free}
Producción
599257099776
Soluciones alternativas
Configurar la salida de Invoke-Command
como una variable y luego seleccionar la cadena y la propiedad de línea parece funcionar para obtener la salida deseada que prefiera.
PowerShell (variación 1)
$var = Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\" };
($var| select-string 'bytes free').Line.Trim();
Producción
11 Dir(s) 36,011,925,504 bytes free
El problema es probabledebido a la invocación cmd /c
y luego la canalización de PowerShell seleccionando la cadena coincidente en la sesión invocada remota. Soluciono ese problema guardando el resultado completo del invoke-command
que regresa correctamente como una variable fuera del invoke-command
y luego analizo esa variable en consecuencia fuera del invoke-command
también.
PowerShell (variación 2)
Este es el mismo trato que el anterior, pero en lugar de agregar una variable a la mezcla, simplemente canalice el Invoke-Command
derecho a la Select-String
consulta.
Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\"; } | select-string 'bytes free';
O incluso algo como esto...
(Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\"; } | select-string 'bytes free').Line.Trim()
Respuesta2
(Vota también la respuesta aceptada si te gustó esta versión TLDR)
Directrices TLDR
Al ejecutar bloques de script de forma remota:
- Si es posible, evite ejecutar cualquier cosa que no sea PowerShell nativo. Por ejemplo, sustituir
cmd /c dir c:\|sls 'bytes free'
por(Get-PSDrive C).Free
. - De lo contrario, realice la menor cantidad de procesamiento en el shell remoto. Por ejemplo, mueva select-string fuera del shell remoto de esta manera:
Invoke-Command cluster02 { cmd /c "dir c:\" } | sls 'bytes free'
.