Soluciones alternativas

Soluciones alternativas

¿Por qué se Invoke-Commandobtienen 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 cluster02y 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 /ccon un comando cmd diry 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-Commandcomo 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 /cy 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-commandque regresa correctamente como una variable fuera del invoke-commandy luego analizo esa variable en consecuencia fuera del invoke-commandtambié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-Commandderecho a la Select-Stringconsulta.

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'.

información relacionada