PowerShell remoto: WinRM, Enter-PSSession e Invoke-Command

PowerShell remoto ejecuta con Invoke-Command la misma orden en todos los equipos de una sala como esta: una fila de puestos de trabajo iguales, con monitor, teclado y ratón, frente a una pared naranja

PowerShell remoto permite ejecutar órdenes en otro equipo sin levantarse de la silla y sin interrumpir a quien lo usa. Sirve para reiniciar un servicio en el servidor de archivos, revisar el espacio en disco de diez servidores a la vez o reiniciar un equipo remoto y esperar a que vuelva. Esta guía explica qué es, cómo habilitar WinRM, cómo usar Enter-PSSession e Invoke-Command, cómo conectarse por SSH con PowerShell 7 y qué errores aparecen por el camino, con escenarios listos para copiar.

Es material de consulta en dos niveles. Si usted no es de sistemas, las primeras secciones le explican qué hace su equipo de TI cuando administra los equipos a distancia y por qué conviene hacerlo así. Si es administrador, el resto trae los comandos, lo que medimos y los errores con su causa. La guía continúa la serie de PowerShell del blog. La guía de PowerShell explica la consola y los scripts, la de Microsoft 365 PowerShell los usuarios y las licencias en la nube, y la de Active Directory PowerShell el directorio local.

Qué es PowerShell remoto

PowerShell remoto es la capacidad de PowerShell para ejecutar comandos en otro equipo y devolver el resultado al suyo. En Windows viaja por WinRM, el servicio de Windows que implementa el protocolo WS-Management. Escucha en el puerto TCP 5985 con HTTP y en el 5986 con HTTPS. Aunque el puerto sea el de HTTP, Microsoft explica en sus consideraciones de seguridad que WinRM cifra toda la comunicación después de la autenticación inicial.

Además, desde PowerShell 7 existe una segunda vía: SSH. Sirve para conectar Windows con Linux o macOS, y la tratamos más abajo.

Hay tres formas de usarlo, y conviene distinguirlas desde el principio:

FormaPara qué sirveComando
Uno a uno, interactivoTrabajar en la consola de otro equipo como si estuviera sentado delanteEnter-PSSession
Uno a muchosEjecutar la misma orden en varios equipos a la vez y recibir todos los resultadosInvoke-Command
Sesión persistenteAbrir una conexión y reutilizarla en varias órdenes, conservando variablesNew-PSSession

Hay un matiz que confunde a muchos: PowerShell remoto no es lo mismo que el parámetro -ComputerName que tienen algunos comandos sueltos, como Get-Service en Windows PowerShell 5.1. Esos comandos usan RPC y no WinRM, y PowerShell 7 quitó varios de ellos. Lo medimos y lo explicamos en su propia sección.

Cuándo conviene PowerShell remoto y cuándo no

El escritorio remoto toma el control de la pantalla de un equipo: es lo adecuado cuando hay que ver lo que ve el usuario. Las herramientas de soporte técnico remoto hacen lo mismo con permiso de la persona. PowerShell remoto es otra cosa: no toca la pantalla ni la sesión del usuario, y la orden queda escrita en un script que se puede repetir y revisar.

Por eso brilla en tres situaciones. La primera, cuando la misma tarea se repite en muchos equipos. La segunda, cuando el equipo es un servidor sin nadie delante. Y la tercera, cuando hay que dejar constancia de qué se hizo. En cambio, no sirve para enseñar algo a un usuario ni para tareas que piden una ventana. Microsoft advierte que los programas con interfaz gráfica y los que piden datos por consola no funcionan bien en una sesión remota.

Requisitos para usar PowerShell remoto

Los requisitos que publica Microsoft se resumen en pocas líneas. Para enviar órdenes no hace falta configurar nada: cualquier Windows con PowerShell puede ser el origen. Lo que hay que preparar es el equipo de destino:

  • WinRM escuchando. En Windows Server viene habilitado de fábrica; Microsoft lo sitúa desde Windows Server 2012 en una página y desde 2012 R2 en otra. En Windows 10 y Windows 11 no viene habilitado.
  • Una cuenta con permiso. De fábrica, solo los miembros del grupo Administradores del equipo de destino pueden conectarse. Microsoft menciona también el grupo Usuarios de administración remota, pero en la misma página aclara que las configuraciones de sesión predeterminadas solo admiten a Administradores. Lo seguro es comprobarlo en el destino con Get-PSSessionConfiguration.
  • El firewall abierto al puerto 5985. Enable-PSRemoting crea la excepción; en redes públicas, solo para la misma subred.
  • Un nombre que se pueda autenticar. En un dominio, con el nombre del equipo, la autenticación es Kerberos y no hace falta nada más. Con una dirección IP, o desde un equipo de un grupo de trabajo, la autenticación pasa a NTLM y hay que añadir el destino a TrustedHosts o usar HTTPS.

Lo que medimos de PowerShell remoto en un Windows 11 sin configurar

Antes de escribir, medimos en un Windows 11 Pro en español, en un grupo de trabajo, sin elevar permisos y sin habilitar nada, lo que ve un administrador antes de empezar. Usamos Windows PowerShell 5.1.26100 y PowerShell 7.6.7:

Qué comprobamosResultado
Servicio «Administración remota de Windows (WS-Management)»Detenido, con inicio manual
Perfil de las tres redes del equipoLas tres públicas
Reglas de firewall de WinRMDos, desactivadas: WINRM-HTTP-In-TCP para redes públicas, limitada a la subred local, y WINRM-HTTP-In-TCP-NoScope para dominio y privadas, sin límite
La regla WINRM-HTTP-In-TCP-PUBLIC que nombra la documentación de MicrosoftNo existe en este equipo: la regla pública se llama WINRM-HTTP-In-TCP
Test-WSMan localhostError a los 4,4-4,5 s: El cliente no puede conectarse con el destino especificado en la solicitud
Invoke-Command -ComputerName localhostEl mismo error, a los 24,5 s en las dos versiones
Invoke-Command contra un nombre, desde el grupo de trabajoRechazado al instante, sin salir a la red, con el error de TrustedHosts
Get-Item WSMan:\localhost\Client\TrustedHostsCon el servicio detenido, la ruta no existe
Test-NetConnection al puerto 5985 cerradoTcpTestSucceeded en False tras 10,6-10,7 s
Tiempos de espera de fábrica de New-PSSessionOptionTres minutos para abrir la sesión y tres para cada operación

Dos conclusiones prácticas salen de ahí. Primera: en un equipo con Windows 11 hay que habilitar WinRM, y si su red figura como pública, Enable-PSRemoting no lo hará sin un parámetro adicional. Segunda: un error de conexión puede tardar más de 20 segundos en aparecer, así que en un script que recorre cien equipos conviene comprobar antes cuáles responden.

Cómo habilitar WinRM

En un equipo

Abra PowerShell como administrador en el equipo que va a recibir las órdenes y ejecute:

Enable-PSRemoting -Force

Según la documentación de Enable-PSRemoting, este comando inicia el servicio WinRM y lo deja en inicio automático, crea un agente de escucha para cualquier dirección IP y abre la excepción del firewall. Además, activa las configuraciones de sesión y reinicia el servicio. También existe la orden clásica winrm quickconfig, que configura el servicio, el agente de escucha y la excepción del firewall.

Solo hay que hacerlo en los equipos que reciben órdenes, no en el suyo. Y como deja un puerto escuchando, Microsoft recomienda hacerlo solo donde haga falta.

Si la red del equipo es pública

Según Microsoft, en Windows 10 y Windows 11 Enable-PSRemoting no habilita nada si el equipo está en una red pública. La primera opción es cambiar la red a privada, si de verdad lo es. La segunda, indicarlo de forma explícita:

Enable-PSRemoting -SkipNetworkProfileCheck -Force

Con ese parámetro, la regla del firewall para redes públicas solo admite equipos de la misma subred. La documentación de Microsoft muestra cómo quitar también ese límite con Set-NetFirewallRule y -RemoteAddress Any, pero eso deja WinRM abierto a cualquier red. No lo recomendamos en un portátil que se conecta a redes de hoteles o aeropuertos.

En todos los equipos de un dominio, con una directiva de grupo

Para cien equipos no se ejecuta Enable-PSRemoting cien veces. En una directiva de grupo se configuran tres cosas. Los nombres son los de Windows en español:

  1. El agente de escucha: Configuración del equipo, Directivas, Plantillas administrativas, Componentes de Windows, Administración remota de Windows (WinRM), Servicio WinRM, Permitir la administración de servidores remotos a través de WinRM. Ahí se indican las direcciones en las que escucha, por ejemplo *.
  2. El servicio: en Configuración de Windows, Configuración de seguridad, Servicios del sistema, el servicio Administración remota de Windows (WS-Management) en inicio automático.
  3. El firewall: una regla de entrada predefinida del grupo Administración remota de Windows.

Para PowerShell 7

PowerShell 7 se instala junto a Windows PowerShell 5.1, sin reemplazarlo. Si ejecuta Enable-PSRemoting desde PowerShell 7, crea dos configuraciones nuevas, una con el nombre corto, como PowerShell.7, y otra con la versión completa. Pero quien se conecta llega de fábrica a la de Windows PowerShell 5.1: en las dos versiones medimos que $PSSessionConfigurationName vale http://schemas.microsoft.com/powershell/Microsoft.PowerShell. Para trabajar con PowerShell 7 en el destino hay que pedirlo:

Enter-PSSession -ComputerName SRV-ARCHIVOS -ConfigurationName PowerShell.7

Comprobar que responde

Desde su equipo, antes de lanzar nada:

Test-WSMan -ComputerName SRV-ARCHIVOS
Test-NetConnection -ComputerName SRV-ARCHIVOS -CommonTCPPort WINRM

La primera orden devuelve la versión del protocolo si WinRM responde. La segunda solo comprueba que el puerto 5985 está abierto: es útil para separar un problema de red de uno de configuración.

Enter-PSSession: una consola en otro equipo

Enter-PSSession abre una consola en el equipo remoto. El indicador cambia y muestra el nombre del equipo entre corchetes, así que todo lo que escriba se ejecuta allí hasta que salga:

Enter-PSSession -ComputerName SRV-ARCHIVOS
Get-Service -Name Spooler
Restart-Service -Name Spooler
Exit-PSSession

Es la forma natural de investigar un problema en un servidor. Pero no sirve dentro de un script: lo comprobamos, y en la línea siguiente a Enter-PSSession el script seguía en el equipo local. Para scripts se usa Invoke-Command.

Con máquinas virtuales de Hyper-V existe una variante que no necesita red: Enter-PSSession -VMName, que explicamos en la guía de Hyper-V.

Invoke-Command: la misma orden en muchos equipos

Invoke-Command envía un bloque de código a uno o varios equipos y le devuelve los resultados. Es la forma de ejecutar la misma orden en toda la oficina, o de reiniciar un equipo remoto sin ir hasta él:

Invoke-Command -ComputerName SRV-ARCHIVOS, SRV-ERP, SRV-DC01 -ScriptBlock {
    Get-Service -Name Spooler
}

De fábrica trabaja con 32 equipos a la vez y el resto espera turno; -ThrottleLimit cambia ese número. Cada resultado llega con la propiedad PSComputerName, que dice de qué equipo viene. Para recorrer una lista larga, guárdela en un archivo de texto, un equipo por línea:

$equipos = Get-Content -Path .\equipos.txt
Invoke-Command -ComputerName $equipos -ScriptBlock { Get-Date } -ErrorAction SilentlyContinue -ErrorVariable fallos
$fallos | ForEach-Object { $_.Exception.Message }

Así, los equipos que no responden no detienen el resto, y $fallos guarda sus errores, cada uno con el nombre del equipo en el mensaje.

Cuatro cosas que cambian cuando el código corre en otro equipo

Las medimos con PowerShell 7 conectado por SSH a tres servidores Linux de prueba. Son propiedades de PowerShell remoto, no de SSH, y Microsoft las describe igual para WinRM:

  1. Sus variables no viajan solas. Una variable definida en su equipo llega vacía al remoto. Con $using: sí viaja: $carpeta devolvió nada y $using:carpeta devolvió la ruta.
  2. Los objetos llegan como copia sin métodos. Un proceso local tenía 19 métodos; el mismo proceso traído del remoto llegó como Deserialized.System.Diagnostics.Process, con solo 2. Llamar a Kill() sobre él falló. La acción tiene que ocurrir dentro del bloque remoto.
  3. El perfil no se carga. Pusimos un perfil en el servidor que definía una variable, y la sesión remota no la vio; Microsoft lo confirma en sus preguntas frecuentes. Lo que necesite el script tiene que ir en el script.
  4. Los errores remotos no detienen el script. Microsoft explica que un error grave en un equipo se trata como error leve, para no parar los demás. Con -ErrorAction Stop en Invoke-Command, en cambio, nuestro catch local sí lo capturó.

Hay un quinto detalle que estropea informes. Cada objeto devuelto trae tres propiedades añadidas, PSComputerName, RunspaceId y PSShowComputerName. Si los exporta a CSV sin elegir columnas, aparecen en el archivo; con Select-Object solo quedan las que usted pide.

Sesiones persistentes con New-PSSession

Cada Invoke-Command -ComputerName abre una conexión y la cierra al terminar. Si va a enviar varias órdenes al mismo equipo, es más rápido abrir una sesión y reutilizarla:

$s = New-PSSession -ComputerName SRV-ERP
Invoke-Command -Session $s -ScriptBlock { $inicio = Get-Date }
Invoke-Command -Session $s -ScriptBlock { (Get-Date) - $inicio }
Remove-PSSession -Session $s

Lo medimos por SSH: diez órdenes en una sesión abierta tardaron 0,25 s, y diez órdenes con una conexión nueva cada vez, 5,10 s. Además, la sesión conserva las variables entre una orden y la siguiente. En la sesión abierta, una variable puesta a 41 devolvió 42 al sumarle uno, y en una conexión suelta llegó vacía.

Cierre siempre las sesiones con Remove-PSSession. Cada una ocupa un proceso en el equipo remoto.

Sesiones desconectadas

Con WinRM, una tarea larga puede seguir en el servidor aunque usted cierre su equipo. Invoke-Command -InDisconnectedSession la deja corriendo, y más tarde Receive-PSSession recoge el resultado, incluso desde otro equipo. Por SSH no existe: lo probamos, y Disconnect-PSSession respondió La operación de desconexión no se admite en el equipo remoto.

PowerShell remoto en un grupo de trabajo: direcciones IP y TrustedHosts

En un dominio, con nombres de equipo, Kerberos autentica a las dos partes y no hace falta nada más. Fuera de ese caso aparece este error, que medimos tal cual en un equipo de un grupo de trabajo. La guía de solución de problemas de Microsoft lo explica con detalle:

El cliente WinRM no puede procesar la solicitud. Si el esquema de autenticación es distinto de Kerberos o si el equipo cliente no está unido a un dominio, se debe usar el transporte HTTPS o agregar el equipo de destino al valor de configuración TrustedHosts.

La salida rápida es añadir el destino a la lista TrustedHosts de su equipo, como administrador, y pasar siempre -Credential:

Start-Service -Name WinRM
Get-Item -Path WSMan:\localhost\Client\TrustedHosts
Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value '192.168.10.20' -Concatenate -Force
$cred = Get-Credential -UserName 'SRV-TALLER\Administrador' -Message 'Cuenta del servidor'
Enter-PSSession -ComputerName 192.168.10.20 -Credential $cred

Hay tres detalles en ese bloque. Primero, en nuestro equipo, con el servicio WinRM detenido, la ruta WSMan:\localhost no existía: por eso el bloque empieza iniciándolo. Segundo, Set-Item reemplaza la lista entera; el parámetro -Concatenate añade el valor nuevo sin borrar los anteriores. Y tercero, Microsoft exige -Credential con NTLM incluso si se conecta con su propio usuario.

El riesgo de TrustedHosts

Microsoft documenta que NTLM comprueba quién es usted, pero no quién es el servidor. Por eso, poner * en TrustedHosts, como muestra algún ejemplo, significa confiar en cualquier equipo que responda con ese nombre. La lista correcta es corta y concreta, y para muchos equipos fuera de un dominio, lo adecuado es HTTPS con un certificado.

Un último caso: según Microsoft, un administrador de otro dominio, aunque sea miembro del grupo Administradores del equipo, llega por la red con privilegios de usuario estándar. La documentación ofrece la entrada de registro LocalAccountTokenFilterPolicy para cambiarlo, pero advierte que desactiva las restricciones remotas del control de cuentas de usuario para todos los usuarios del equipo. Antes de tocarla, busque otra salida, como una cuenta del propio dominio.

PowerShell remoto por SSH con PowerShell 7

PowerShell 7 añade una segunda vía: SSH. Con ella, un Windows administra servidores Linux, y al revés, porque Microsoft ya no admite WinRM fuera de Windows. Los comandos son los mismos, pero con -HostName en lugar de -ComputerName, como explica Microsoft en su guía de comunicación remota por SSH. Windows PowerShell 5.1 no tiene esa opción: lo comprobamos, y -HostName solo existe en PowerShell 7.

Lo que necesita el servidor

El servidor necesita PowerShell 7 instalado, el servicio SSH y una línea en su configuración que le diga que existe el subsistema de PowerShell. En Ubuntu, después de instalar PowerShell:

sudo apt install openssh-server
echo 'Subsystem powershell /usr/bin/pwsh -sshs -nologo' | sudo tee /etc/ssh/sshd_config.d/20-powershell.conf
sudo systemctl restart ssh

Para la autenticación, lo recomendable es una clave en lugar de una contraseña. Cómo crearla y copiarla al servidor sin errores lo explicamos en la guía de SSH. Si el servidor es Windows, Microsoft documenta un fallo de OpenSSH para Windows con las rutas que llevan espacios. Por eso, la línea del subsistema tiene que usar el nombre corto de la carpeta o un enlace simbólico.

Conectarse desde Windows

$s = New-PSSession -HostName srv-linux01 -UserName admin -KeyFilePath "$HOME\.ssh\id_ed25519"
Invoke-Command -Session $s -ScriptBlock { Get-Content -Path /etc/os-release -TotalCount 2 }
Remove-PSSession -Session $s

Para varios servidores, Invoke-Command -HostName acepta una lista:

Invoke-Command -HostName srv-linux01, srv-linux02 -UserName admin -KeyFilePath "$HOME\.ssh\id_ed25519" -ScriptBlock { hostname }

Lo que medimos

Montamos un laboratorio aislado: cuatro contenedores con Ubuntu 24.04, OpenSSH 9.6 y PowerShell 7.6.7, escuchando solo en direcciones locales. Tres tenían el subsistema de PowerShell y uno no. El cliente fue PowerShell 7.6.7 en Windows 11, con el cliente SSH 9.5 que trae Windows, sin tocar la configuración SSH del equipo:

PruebaResultado
Abrir una sesión0,56 s
Diez órdenes en una sesión abierta0,25 s
Diez órdenes, con una conexión nueva para cada una5,10 s
Tres servidores que tardan 3 s cada uno, con un solo Invoke-Command4,01 s, en paralelo
Los mismos tres, uno detrás de otro con foreach10,53 s
Tres sesiones abiertas: sin límite, con -ThrottleLimit 2 y con -ThrottleLimit 13,06 s, 6,05 s y 9,08 s
-ThrottleLimit junto con -HostNameRechazado: ese conjunto de parámetros no lo admite
Copiar 20 MB al servidor con Copy-Item -ToSessionEntre 12,6 y 17,7 s en cuatro pasadas
Traer los mismos 20 MB con Copy-Item -FromSessionEntre 3,8 y 5,0 s
Copiar los mismos 20 MB con scp0,58 s
Copy-Item -ToSession hacia una carpeta que no existeError: no crea la carpeta
Invoke-Command -FilePath con un script del equipo localSe ejecuta en el servidor sin dejar copia del script
-SSHConnection, la forma con una tabla de datos por servidorNo conectó en ninguno de nuestros once intentos
Disconnect-PSSessionNo se admite por SSH

Qué concluimos de las pruebas por SSH

Tres conclusiones salen de esta tabla. Primera: para muchas órdenes, abra una sesión y reutilícela. Segunda: para limitar cuántos servidores trabajan a la vez por SSH, abra las sesiones con New-PSSession y aplique -ThrottleLimit a Invoke-Command -Session. Tercera: Copy-Item por la sesión sirve para un archivo de configuración, pero para archivos grandes fue entre 21 y 30 veces más lento que scp.

Sobre -SSHConnection, unas veces se conectó al puerto 22 aunque la tabla decía otro, y otras agotó el tiempo de espera, incluso uno de cero segundos. La documentación da como valor predeterminado una espera ilimitada. Con -HostName y -Port, la misma conexión funcionó, así que nuestros ejemplos usan esa forma.

Cuando la conexión por SSH falla

Cuando una conexión por SSH falla, PowerShell muestra siempre el mismo mensaje: El proceso de transporte SSH ha finalizado repentinamente. La causa real está en la línea que escribe SSH justo encima, y la medimos en cuatro casos:

Línea de SSHCausa
Permission denied (publickey)La clave no está autorizada en el servidor
Connection refusedNada escucha en ese puerto
subsystem request failed on channel 0Falta la línea del subsistema de PowerShell en el servidor
Host key verification failedLa huella del servidor no está en la lista de equipos conocidos

Por último, Microsoft documenta dos límites de SSH frente a WinRM: no admite configuraciones de sesión propias ni JEA, la administración con el mínimo de permisos que explicamos más abajo.

Comandos con -ComputerName propio, que no son PowerShell remoto

Algunos comandos tienen su propio parámetro -ComputerName y no usan WinRM, sino RPC. Microsoft lo advierte en la documentación de requisitos. En Windows PowerShell 5.1, por ejemplo, Get-Service -ComputerName localhost leyó 313 servicios con WinRM detenido. Esto tiene dos consecuencias: funcionan sin habilitar WinRM, pero necesitan otros puertos en el firewall, y PowerShell 7 quitó o cambió varios de ellos. Microsoft lo resume en sus diferencias entre Windows PowerShell y PowerShell 7. Lo medimos en las dos versiones, contra el equipo local y contra un nombre que no puede existir:

ComandoWindows PowerShell 5.1PowerShell 7.6
Get-Service, Set-Service, Get-ProcessTienen -ComputerName y usan RPCNo tienen -ComputerName: hay que usar Invoke-Command
Test-Connection-ComputerName-TargetName, y además -TcpPort
Stop-ComputerError de RPC: El servidor RPC no está disponibleError de WinRM: ahora usa WinRM
Restart-Computer-Protocol con DCOM o WSManSin -Protocol: según Microsoft, solo WinRM
Get-WinEventRPCRPC, igual
Get-WmiObject, Get-EventLogIncluidosNo vienen; PowerShell 7 los carga desde Windows PowerShell en segundo plano: 3,1 s la primera vez
Get-CimInstanceWinRMWinRM

Un error que confunde al diagnosticar

Hay un detalle que confunde al diagnosticar. En Windows PowerShell 5.1, Get-Service -ComputerName con un equipo que no existe y el nombre de un servicio respondió No se encuentra ningún servicio con el nombre 'Spooler'. El mensaje habla del servicio cuando el problema es el equipo.

La conclusión práctica es una sola: un script nuevo debe usar Invoke-Command. Así funciona igual en las dos versiones, usa un único puerto y aprovecha el paralelismo.

El problema del segundo salto en PowerShell remoto

Usted se conecta al servidor A y, desde la sesión, intenta leer una carpeta compartida del servidor B. Falla con acceso denegado, aunque su cuenta tenga permiso en B. Microsoft lo llama el problema del segundo salto: sus credenciales no viajan de A a B.

Microsoft ordena las soluciones por preferencia, y cada una tiene un precio:

SoluciónLo que dice Microsoft
CredSSPEquilibra facilidad y seguridad, pero guarda sus credenciales en el servidor A: si A está comprometido, el atacante las obtiene. Viene desactivado y solo debería usarse en entornos de máxima confianza
Delegación restringida de Kerberos basada en recursosMás segura y no guarda credenciales, pero no permite un segundo salto por WinRM: sirve para llegar a recursos como una carpeta compartida
Delegación restringida de KerberosSegura, pero exige un administrador del dominio y tampoco permite el segundo salto por WinRM
JEAPuede dar la mejor seguridad, pero exige más configuración en cada servidor intermedio
Pasar credenciales dentro del bloqueLa más simple: no exige configurar nada en los servidores, pero obliga a pasar la credencial en cada orden

La última es la más útil para una tarea puntual:

$cred = Get-Credential -UserName 'EMPRESA\admin.ti' -Message 'Cuenta para el segundo salto'
Invoke-Command -ComputerName SRV-ERP -Credential $cred -ScriptBlock {
    Invoke-Command -ComputerName SRV-ARCHIVOS -Credential $using:cred -ScriptBlock { hostname }
}

Seguridad de PowerShell remoto

PowerShell remoto es una puerta de administración, así que se protege como tal. Microsoft lo considera la forma recomendada de administrar Windows, y estos son los puntos que conviene revisar:

  • Quién puede entrar. De fábrica, solo los administradores del equipo de destino. Cada sesión corre con los permisos del usuario que se conecta.
  • Desde dónde. La regla del firewall para redes públicas solo admite la subred local, y Microsoft advierte de que quitar ese límite expone el equipo. WinRM no debería ser accesible desde Internet.
  • Con qué autenticación. Kerberos, en un dominio, comprueba a las dos partes. NTLM no comprueba al servidor, por eso la lista TrustedHosts debe ser corta, y por eso existe HTTPS en el puerto 5986.
  • CredSSP desactivado, salvo una necesidad concreta y temporal.
  • Con el mínimo de permisos. JEA, de Just Enough Administration, permite que alguien reinicie un servicio sin ser administrador del servidor, limitando los comandos disponibles en la sesión. Solo funciona por WinRM.
  • Con registro. Windows puede registrar los bloques de script que se ejecutan; Microsoft lo explica en su documentación sobre el registro de PowerShell.

Errores frecuentes de PowerShell remoto y cómo resolverlos

Los mensajes de esta tabla los obtuvimos en nuestras pruebas, en Windows en español. Las causas salen de la documentación de Microsoft y de esas mismas pruebas:

MensajeCausa probableQué hacer
El cliente no puede conectarse con el destino especificado en la solicitudWinRM no está habilitado en el destino, o el firewall bloquea el puerto 5985Ejecutar Enable-PSRemoting en el destino y comprobar el puerto con Test-NetConnection
El cliente WinRM no puede procesar la solicitudConexión con una IP o desde un grupo de trabajo: no hay KerberosAñadir el destino a TrustedHosts y usar -Credential, o configurar HTTPS
No se encuentra la ruta de acceso 'WSMan:\localhost\Client\TrustedHosts' porque no existe.El servicio WinRM está detenido en su propio equipoStart-Service WinRM, como administrador
No se encuentra un parámetro que coincida con el nombre de parámetro "ComputerName".Un comando de Windows PowerShell 5.1 ejecutado en PowerShell 7Usar Invoke-Command
El servidor RPC no está disponible.Un comando con -ComputerName propio, que usa RPC y no WinRMRevisar el equipo y el firewall, o usar Invoke-Command
El proceso de transporte SSH ha finalizado repentinamenteFallo de SSH: la línea anterior dice cuálVer la tabla de SSH
La operación de desconexión no se admite en el equipo remotoSesión por SSHUsar WinRM para tareas desconectadas
El conjunto de parámetros no se puede resolver-ThrottleLimit junto con -HostNameAbrir sesiones con New-PSSession y limitar en Invoke-Command -Session
Acceso denegado a una carpeta compartida desde la sesiónEl segundo saltoPasar la credencial dentro del bloque

Escenarios de PowerShell remoto listos para copiar

Los nombres de equipo son de ejemplo. Todos los bloques usan WinRM y funcionan en Windows PowerShell 5.1 y en PowerShell 7.

1. Comprobar qué equipos aceptan PowerShell remoto

$equipos = Get-Content -Path .\equipos.txt
foreach ($equipo in $equipos) {
    $ok = $null -ne (Test-WSMan -ComputerName $equipo -ErrorAction SilentlyContinue)
    [pscustomobject]@{ Equipo = $equipo; PowerShellRemoto = $ok }
}

2. Reiniciar un equipo remoto con PowerShell y esperar a que vuelva

Restart-Computer -ComputerName PC-CONTAB-07 -Force -Wait -For PowerShell -Timeout 600 -Delay 10

Es la forma más directa de reiniciar un equipo remoto. Con -Force, el reinicio es inmediato: avise antes, porque quien esté trabajando pierde lo que no haya guardado. -Wait -For PowerShell no devuelve el control hasta que el equipo vuelve a aceptar PowerShell remoto, con un máximo de 600 segundos. Si prefiere dar tiempo al usuario, programe el reinicio con un aviso de cinco minutos:

Invoke-Command -ComputerName PC-CONTAB-07 -ScriptBlock {
    shutdown.exe /r /t 300 /c 'El equipo se reiniciará en cinco minutos por mantenimiento.'
}

3. Reiniciar el servicio de impresión en varios equipos

Invoke-Command -ComputerName PC-CONTAB-07, PC-CONTAB-08 -ScriptBlock {
    Restart-Service -Name Spooler -PassThru
} | Select-Object PSComputerName, Name, Status

4. Espacio libre en disco de los servidores, en un CSV

$equipos = 'SRV-ARCHIVOS', 'SRV-ERP', 'SRV-DC01'
Invoke-Command -ComputerName $equipos -ScriptBlock {
    Get-CimInstance -ClassName Win32_LogicalDisk -Filter 'DriveType = 3' |
        Select-Object DeviceID,
            @{ n = 'TotalGB'; e = { [math]::Round($_.Size / 1GB, 1) } },
            @{ n = 'LibreGB'; e = { [math]::Round($_.FreeSpace / 1GB, 1) } }
} | Select-Object PSComputerName, DeviceID, TotalGB, LibreGB |
    Export-Csv -Path .\espacio-en-disco.csv -NoTypeInformation -Encoding UTF8

El Select-Object final deja fuera las columnas que añade PowerShell remoto. Si el archivo va a llevar tildes, revise antes cómo exportar a CSV sin perder las tildes, porque Windows PowerShell 5.1 y PowerShell 7 no escriben igual.

5. Ver quién tiene la sesión iniciada en cada equipo

Invoke-Command -ComputerName PC-CONTAB-07, PC-CONTAB-08 -ScriptBlock {
    (Get-CimInstance -ClassName Win32_ComputerSystem).UserName
}

6. Copiar un archivo pequeño a varios equipos

$sesiones = New-PSSession -ComputerName PC-CONTAB-07, PC-CONTAB-08
Invoke-Command -Session $sesiones -ScriptBlock { New-Item -Path 'C:\Plantillas' -ItemType Directory -Force | Out-Null }
foreach ($s in $sesiones) {
    Copy-Item -Path .\plantilla-factura.xlsx -Destination 'C:\Plantillas\' -ToSession $s
}
Remove-PSSession -Session $sesiones

La segunda línea crea la carpeta, porque en nuestra prueba Copy-Item no la creó. Para carpetas grandes, mejor Robocopy sobre una carpeta compartida.

7. Ejecutar un script de su equipo en varios servidores

Invoke-Command -ComputerName (Get-Content -Path .\equipos.txt) -FilePath .\inventario.ps1

El script viaja con la orden: no hace falta copiarlo antes a cada servidor.

8. Habilitar el escritorio remoto en otro equipo

Invoke-Command -ComputerName PC-CONTAB-07 -ScriptBlock {
    Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 0
    Enable-NetFirewallRule -Group '@FirewallAPI.dll,-28752'
}

Los ejemplos que circulan usan -DisplayGroup 'Remote Desktop'. En nuestro Windows en español esa orden falló, porque el nombre visible del grupo es «Escritorio remoto». En cambio, -Group '@FirewallAPI.dll,-28752' encontró las tres reglas, y funciona en cualquier idioma: es el nombre interno del grupo. Antes de habilitarlo en un equipo, recuerde que Microsoft solo lo recomienda en redes de confianza.

9. Últimos apagados inesperados en los servidores

$equipos = 'SRV-ARCHIVOS', 'SRV-ERP', 'SRV-DC01'
Invoke-Command -ComputerName $equipos -ScriptBlock {
    Get-WinEvent -FilterHashtable @{ LogName = 'System'; Id = 41, 6008 } -MaxEvents 5 -ErrorAction SilentlyContinue |
        Select-Object TimeCreated, Id, ProviderName
} | Select-Object PSComputerName, TimeCreated, Id, ProviderName

Qué significa cada evento lo explicamos en la guía del Visor de eventos.

10. Una tarea larga que sigue aunque usted se desconecte

Invoke-Command -ComputerName SRV-ARCHIVOS -InDisconnectedSession -SessionName Inventario -ScriptBlock {
    Get-ChildItem -Path D:\Datos -Recurse -File | Measure-Object -Property Length -Sum
}
Get-PSSession -ComputerName SRV-ARCHIVOS -Name Inventario | Receive-PSSession

La primera orden deja la tarea corriendo en el servidor. La segunda, ejecutada más tarde, recoge el resultado.

Recomendaciones para usar PowerShell remoto

  1. Habilite WinRM donde haga falta, con una directiva de grupo si son muchos equipos, y deje la regla de redes públicas como viene.
  2. Use nombres de equipo, no direcciones IP, dentro de un dominio: así funciona Kerberos y no hace falta TrustedHosts.
  3. Mantenga TrustedHosts corto. Nunca un asterisco.
  4. Escriba los scripts con Invoke-Command, no con los -ComputerName antiguos: funcionan igual en Windows PowerShell 5.1 y en PowerShell 7.
  5. Reutilice sesiones cuando envíe varias órdenes al mismo equipo, y ciérrelas al terminar.
  6. Pase las variables con $using: y haga dentro del bloque las acciones sobre objetos remotos.
  7. Compruebe antes de recorrer cien equipos: un error de conexión tarda más de 20 segundos en aparecer.
  8. Evite CredSSP: para el segundo salto, pase la credencial dentro del bloque.
  9. Para archivos grandes, no use Copy-Item por la sesión: use scp, Robocopy o una carpeta compartida.

Lo que no probamos

No ejecutamos PowerShell remoto por WinRM entre dos equipos Windows. Habilitarlo en el equipo de pruebas exigía permisos de administrador y cambiaba su configuración. Lo que esta guía dice de WinRM sale de la documentación de Microsoft y de lo que medimos en el lado del cliente.

Tampoco probamos HTTPS en el puerto 5986, CredSSP, la delegación de Kerberos, JEA, las directivas de grupo ni Windows como servidor SSH. Las pruebas por SSH se hicieron contra servidores Linux en contenedores. Los tiempos son de un laboratorio local, sin la latencia de una red real.

Administración remota con orden y registro

PowerShell remoto ahorra horas cuando la misma tarea se repite en muchos equipos, pero exige decidir quién puede entrar, desde dónde y con qué cuenta. En KHARONTE administramos puestos de trabajo y servidores a distancia, y cada intervención queda registrada en nuestra mesa de ayuda TI.

Si su empresa quiere delegar la operación diaria de sus equipos, nuestros servicios administrados de TI cubren el soporte, la infraestructura de TI y el monitoreo. Puede ver el detalle de nuestros servicios de TI para empresas.

Preguntas frecuentes

¿PowerShell remoto es lo mismo que el escritorio remoto?

No. El escritorio remoto toma el control de la pantalla y la sesión del usuario. PowerShell remoto ejecuta órdenes sin tocar la pantalla, en uno o en muchos equipos a la vez, y sin interrumpir a quien trabaja.

¿Qué puerto usa PowerShell remoto?

Por WinRM, el TCP 5985 con HTTP y el TCP 5986 con HTTPS. Microsoft explica que, incluso por el 5985, WinRM cifra la comunicación después de la autenticación inicial. Por SSH, el puerto del servicio SSH, normalmente el 22.

¿Cómo habilito WinRM en Windows 11?

Abra PowerShell como administrador y ejecute Enable-PSRemoting -Force. Si la red del equipo es pública, cámbiela a privada o añada -SkipNetworkProfileCheck. En una empresa con dominio, lo práctico es una directiva de grupo.

¿Puedo administrar servidores Linux con PowerShell remoto?

Sí, con PowerShell 7 y SSH: el servidor necesita PowerShell 7 y la línea del subsistema en la configuración de SSH. Microsoft ya no admite WinRM fuera de Windows.

¿Por qué mi script funciona en local y falla en remoto?

Hay tres causas comunes. Una variable local que no se pasó con $using:; un perfil, que en la sesión remota no se carga; y el segundo salto, al intentar llegar a otro equipo desde la sesión.

Hablemos de la TI de su empresa

Cuéntenos qué necesita su operación y le enviamos una propuesta por escrito. Cada línea del portafolio se contrata por separado.

Compartir este artículo

Últimas entradas

Escríbanos ahora