Orquestación multi-máquina con PowerShell jobs y runspaces

Última actualización: 17/12/2025
Autor: Isaac
  • PowerShell ofrece varias opciones de paralelismo (jobs, runspaces, pools y workflows) para ejecutar tareas en múltiples máquinas de forma simultánea.
  • Runspaces y RunspacePool permiten un control fino del rendimiento, mientras que Configuration Manager y Azure Arc facilitan la automatización masiva en entornos híbridos.
  • Los flujos de trabajo PowerShell y los runbooks de Automation aportan ejecución paralela, puntos de control y reanudación tras fallos a gran escala.
  • InlineScript y los módulos de integración amplían las capacidades del workflow cuando necesitas cmdlets específicos o lógica PowerShell “pura” en escenarios complejos.

cómo ver el historial de comandos en Powershell y CMD

Cuando empiezas a hacer automatización a gran escala con PowerShell, tarde o temprano te topas con el mismo muro: los scripts secuenciales se quedan cortos. Apagar decenas de máquinas, parchear cientos de servidores o procesar teras de ficheros en un único hilo es una receta perfecta para perder horas… o días.

La buena noticia es que PowerShell tiene varias formas de orquestar trabajo en paralelo entre múltiples máquinas: jobs, runspaces, pools de runspaces, flujos de trabajo y runbooks en plataformas como Service Management Automation o Azure Automation. Elegir bien la herramienta y saber combinarlas marca la diferencia entre un script que “funciona” y una solución realmente escalable y robusta.

Por qué necesitas orquestación multi-máquina en PowerShell

En escenarios reales, como parchear y reiniciar un montón de servidores Windows, apagar instancias de varias máquinas virtuales a la vez o recorrer 10 TB de datos para localizar vídeos, ejecutar las tareas de una en una es asumir que el tiempo no importa. Con un simple bucle, PowerShell hará el trabajo, sí, pero el cuello de botella será brutal.

Cuando hablamos de enviar órdenes simultáneas a muchos nodos, hay tres retos clave: cómo lanzar tareas en paralelo sin volverte loco con la sincronización, cómo mantener una buena escalabilidad sin fundir la máquina de orquestación y cómo filtrar eventos críticos y reintentos sin perder el estado de lo que ya llevas hecho.

Opciones de paralelismo en PowerShell: jobs, runspaces y flujos de trabajo

PowerShell ofrece varios mecanismos para ejecutar trabajo en paralelo, cada uno con sus ventajas y sus pegas. A grandes rasgos, puedes optar por jobs tradicionales, runspaces (y pools de runspaces) o flujos de trabajo PowerShell basados en Windows Workflow Foundation, que a su vez se integran con runbooks de Automation.

Los jobs de PowerShell son fáciles de usar y muy cómodos para tareas sencillas en segundo plano, pero no son la opción más afinada cuando quieres exprimir el rendimiento. Para escenarios más exigentes en concurrencia, los runspaces y sus pools permiten un control fino de hilos, mientras que los flujos de trabajo y los runbooks añaden orquestación avanzada, resiliencia y ejecución distribuida.

Runspaces y RunspacePool: la base del paralelismo fino

Un runspace no es más que un entorno de ejecución de PowerShell embebido dentro de tu proceso .NET. Puedes crear uno, cargar comandos, ejecutarlos y cerrar ese contexto. Si creas muchos runspaces independientes con la misma configuración, empiezas a desperdiciar recursos en inicializaciones repetidas.

Para evitar ese desperdicio existe RunspacePool (System.Management.Automation.Runspaces.RunspacePool), un grupo de espacios de ejecución que comparten características comunes. En lugar de generar cientos de runspaces “sueltos”, creas un pool y dejas que PowerShell reutilice de forma eficiente esos contextos, mejorando notablemente el rendimiento en escenarios muy concurridos.

Ejemplo práctico de uso de RunspacePool desde C#

Imagina que quieres lanzar un comando tipo Get-Process wmi* desde una aplicación host en C# y hacerlo de forma asíncrona, aprovechando un pool de runspaces. El patrón es siempre el mismo: crear el pool, abrirlo, asociar un objeto PowerShell al pool, añadir comandos, invocarlos de forma asíncrona y recuperar la salida.

En C#, la lógica se basaría en crear el pool con RunspaceFactory.CreateRunspacePool(), abrirlo y montar un objeto PowerShell con ese pool asignado en la propiedad RunspacePool. Luego le añades el comando con AddCommand(«Get-Process»).AddArgument(«wmi*») y llamas a BeginInvoke para lanzar la ejecución asincrónica, recogiendo después los resultados con EndInvoke en una colección PSDataCollection<PSObject>.

Una vez tienes esa colección, puedes recorrer cada PSObject y extraer propiedades como ProcessName e Id para mostrarlas por consola o procesarlas según te convenga, por ejemplo para gestionar procesos y tareas en Windows. Este enfoque ilustra cómo usar el mismo pool de runspaces para diferentes invocaciones, evitando crear y destruir espacios de ejecución de forma masiva e ineficiente.

Paralelizar tareas intensivas de disco: ejemplo de escaneo de 10 TB

Un caso muy típico es el de alguien que, con un simple Get-ChildItem -Recurse, recorre un volumen inmenso (por ejemplo, Y:\ con 10 TB) buscando archivos de vídeo (.mp4, .avi, .mkv) y filtrando por extensión. El script secuencial puede ser tan simple como recorrer todo, filtrar con Where-Object y mostrar la ruta completa.

El problema surge cuando ese mismo script se ejecuta en un árbol de directorios gigantesco: el tiempo de exploración se vuelve inasumible. Para exprimir más rendimiento, la idea lógica es fragmentar el trabajo en varios hilos: por ejemplo, entre 5 y 10 threads, cada uno analizando un subconjunto de carpetas o de unidades de red.

Una estrategia razonable sería que un primer runspace se encargara de recopilar y almacenar las carpetas en un array compartido, un segundo runspace se dedicara a filtrar los archivos de vídeo dentro de esas carpetas y un tercero se encargara de mover los ficheros ya clasificados a su destino. Esta división en etapas (descubrir rutas, filtrar tipos, mover contenido) permite modularizar y paralelizar el flujo.

Para implementar algo así en PowerShell puro, puedes tirar de runspaces manuales o módulos como PoshRSJob que abstraen parte de la complejidad, pero el concepto sigue siendo el mismo: repartir el árbol de directorios en bloques, lanzar varios hilos en paralelo y sincronizar el resultado sin pisarte recursos ni saturar el sistema de archivos.

  Cómo abrir y analizar archivos ETL en Windows Performance Analyzer (WPA)

Ejecutar funciones en paralelo para apagar múltiples máquinas

Otro escenario de libro es el de un script que apaga instancias en varias máquinas virtuales, pero que lo hace de forma secuencial porque cada instancia tiene su función propia con los comandos específicos. Mientras una VM se apaga, el resto está esperando turno, y la ventana de mantenimiento se alarga sin necesidad.

Para evitar este cuello de botella, lo ideal es lanzar cada función de apagado como un trabajo paralelo o usar runspaces que llamen en paralelo a las funciones. La diferencia respecto a los jobs tradicionales es que con runspaces puedes controlar mejor el número máximo de hilos activos y la manera en que compartes datos entre ellos.

Si solo quieres concurrencia básica, puedes usar jobs de PowerShell para disparar todas las funciones a la vez y luego esperar a que finalicen. Si buscas un control más fino del rendimiento y la reutilización de contexto, un RunspacePool te permitirá tener, por ejemplo, 5 hilos trabajando en paralelo apagando máquinas, en lugar de saturar el host con decenas de procesos sueltos.

Orquestar parches y reinicios de muchos servidores Windows

Quien viene del mundo Linux con Ansible y Python suele tener muy claro el concepto de ejecución masiva en paralelo, pero cuando aterriza en PowerShell, se encuentra con varias opciones dispersas: workflows, jobs, runspaces, sin saber muy bien por dónde empezar para parchear y reiniciar un montón de servidores a la vez.

El problema clásico es un script que gestiona un solo servidor por iteración, aplicando parches, reiniciando y esperando a que vuelva a levantar. Si tienes decenas o cientos de nodos, este enfoque secuencial se vuelve impracticable. Para solventarlo, puedes apoyarte en trabajos remotos, runspaces o directamente en flujos de trabajo PowerShell con construcciones paralelas como ForEach -Parallel.

Cuando además trabajas con clústeres y dependencias entre nodos, necesitas no solo paralelismo, sino cierta lógica de orquestación: por ejemplo, evitar que se reinicien al mismo tiempo todos los nodos de un clúster. Aquí es donde un flujo de trabajo bien diseñado, o un runbook en Azure Automation o Service Management Automation, puede facilitarte la vida marcando secuencias y paralelismos de forma declarativa.

Automatizar incorporación masiva a Azure Arc con Configuration Manager

Si tienes un entorno híbrido, es muy común querer conectar un gran número de servidores Windows o Linux a Azure Arc usando Configuration Manager (ConfigMgr / SCCM). ConfigMgr incluye de serie la capacidad de ejecutar scripts de PowerShell sobre colecciones de dispositivos, lo que lo convierte en una herramienta muy útil para orquestación multi-máquina.

Mediante un único script de PowerShell puedes automatizar la incorporación a Azure Arc en todos los servidores que cumplan los requisitos. Antes de nada conviene comprobar que tu suscripción y tus recursos cumplen las condiciones (regiones soportadas, limitaciones, etc.) y revisar las recomendaciones de diseño y supervisión para despliegues a gran escala en Azure.

Un detalle importante es la función de conexión automática de instancias de SQL Server habilitadas para Azure Arc. Si conectas un servidor habilitado para Arc que ya tenga SQL Server instalado, las instancias de SQL se pueden registrar automáticamente en Arc, proporcionando inventario avanzado y capacidades extra de administración de bases de datos y motor.

Como parte de ese proceso, se despliega una extensión en el servidor conectado y se aplican nuevos roles y permisos sobre SQL Server y las bases de datos. Si prefieres que esos SQL no se conecten de forma automática, puedes evitarlo añadiendo una etiqueta al servidor Windows o Linux con el nombre ArcSQLServerExtensionDeployment y el valor Disabled antes o durante la incorporación.

Requisitos previos para ejecutar scripts de PowerShell desde Configuration Manager

Para aprovechar la ejecución de scripts de PowerShell a través de ConfigMgr, necesitas cumplir ciertas condiciones de versión y permisos. Lo primero es asegurarte de que usas Configuration Manager 1706 o superior, ya que las versiones anteriores no incorporan esta funcionalidad de scripts integrada.

A nivel de seguridad, la cuenta con la que trabajas debe tener permisos de Crear sobre “Scripts de SMS” para poder importar y definir nuevos scripts. Además, la aprobación de scripts está separada de la creación: solo las cuentas con permiso de Aprobar para “Scripts de SMS” pueden validar o denegar scripts para que se usen en producción.

Para finalmente realizar la ejecución sobre colecciones, la cuenta necesita permisos de Ejecutar script para “Recopilaciones”. Otro punto clave es revisar la configuración predeterminada de PowerShell en el Agente de equipo de ConfigMgr, verificando que la directiva de ejecución (Execution Policy) está establecida en Omitir, de forma que los scripts puedan ejecutarse sin bloqueos innecesarios.

Generación del principal de servicio y script de instalación para Azure Arc

Antes de lanzar el script masivo desde Configuration Manager para incorporar servidores a Azure Arc, hay que preparar un par de piezas: un principal de servicio con permisos adecuados y el script de instalación generado desde el portal de Azure.

En primer lugar, debes seguir los pasos para crear un principal de servicio específico para incorporación masiva, asignándole el rol de “Incorporación de Azure Connected Machine” y limitando su ámbito a la zona de aterrizaje correspondiente en Azure. Es vital guardar el secreto (client secret) del principal, pues más adelante tendrás que incrustarlo o referenciarlo desde el script de instalación.

  Cómo listar LWPs y procesos en Linux y controlarlos al detalle

Después, en el portal de Azure, se genera el script de instalación de la extensión de Azure Arc para máquinas conectadas. Ese script no se debe ejecutar directamente en PowerShell en este punto, sino que se conservará para importarlo o pegarlo dentro del asistente de configuración de scripts de Configuration Manager, donde se adaptará añadiendo el secreto del principal de servicio.

Crear, aprobar y ejecutar el script en Configuration Manager

Una vez tienes el script de Azure Arc listo, el siguiente paso es dar de alta el script en ConfigMgr. Desde la consola, en el área de Biblioteca de software, puedes acceder al nodo de Scripts y usar la opción Crear script para iniciar el asistente.

En ese asistente defines un nombre reconocible para el script (por ejemplo, “Onboard Azure Arc”), seleccionas PowerShell como lenguaje y utilizas la opción de importación para cargar el archivo generado en el portal de Azure o pegar su contenido directamente. Es aquí donde editas el texto del script para incorporar el secreto del principal de servicio que creaste previamente.

Tras finalizar el asistente, el script aparecerá en la lista con el estado de “Esperando aprobación”. Con un usuario que tenga permisos para aprobar scripts, vuelves al mismo nodo de Scripts, seleccionas el script deseado y eliges Aprobar o denegar. En el cuadro de diálogo seleccionas Aprobar, completas el asistente y confirmas que el estado del script pasa a “Aprobado”.

Para lanzar el script sobre una colección de dispositivos, cambias a la sección de Recursos y cumplimiento, entras en Recopilaciones de dispositivos, eliges la colección que quieras (por ejemplo, “Todos los servidores habilitados para Arc”) y seleccionas Ejecutar script. En el asistente, escoges el script que has creado y aprobado, y al completarlo, Configuration Manager se encargará de ejecutar el script en todos los dispositivos de la colección.

El estado de esa ejecución se puede controlar desde las vistas de monitorización de scripts, donde verás si la instalación del agente de máquina conectada se ha realizado correctamente en cada servidor. Los equipos que se conecten de manera satisfactoria aparecerán posteriormente en el portal de Azure como servidores habilitados para Azure Arc.

Runbooks y flujos de trabajo de PowerShell en Automation

Más allá de ConfigMgr, muchas organizaciones utilizan Service Management Automation o Azure Automation para gestionar tareas complejas de orquestación. En estos entornos, los runbooks de tipo PowerShell Workflow son la piedra angular: scripts escritos con sintaxis PowerShell, pero ejecutados sobre Windows Workflow Foundation.

La estructura de un runbook de Automation basado en workflow es prácticamente idéntica para SMA y para Azure Automation, aunque normalmente operan sobre recursos distintos (on-premises frente a nube). Gracias a la integración con Workflow Foundation, estos runbooks ofrecen paralelismo nativo, puntos de control con persistencia del estado y capacidad de reanudación tras fallos.

Un flujo de trabajo de PowerShell se declara con la palabra clave Workflow seguida del nombre, y encierra sus comandos entre llaves. Ese nombre debe coincidir con el nombre del runbook y, si se importa desde un archivo, también con el nombre del archivo .ps1. La forma habitual es seguir el patrón Verbo-Sustantivo estándar en PowerShell.

Estructura, parámetros y limitaciones de los flujos de trabajo

Para aceptar entradas, el workflow utiliza un bloque Param tradicional de PowerShell, donde puedes definir parámetros obligatorios u opcionales con el atributo seguido del tipo y nombre del parámetro. Cuando ejecutes el runbook desde el portal o la API, se solicitarán esos valores.

Aunque el flujo de trabajo se escriba con la misma sintaxis básica que un script de PowerShell, la ejecución real se hace mediante Windows Workflow Foundation, y eso introduce ciertas limitaciones y diferencias de comportamiento. Es importante revisar la documentación sobre diferencias sintácticas entre flujos de trabajo y scripts para evitar sorpresas con comandos no soportados o comportamientos especiales.

Muchos cmdlets estándar de PowerShell se convierten automáticamente en actividades de Workflow cuando se ejecutan dentro de un flujo de trabajo. Para aquellos que no tienen una actividad equivalente, el motor los envuelve en una actividad InlineScript de forma transparente, o exige que tú mismo los coloques bajo un bloque InlineScript explícito si están en la lista de cmdlets excluidos.

Actividades, módulos de integración y carga automática

Dentro de un workflow, cada actividad representa una tarea concreta, de la misma forma que un script se compone de uno o varios cmdlets. Windows Workflow Foundation controla la ejecución de estas actividades, permitiendo características como la reanudación tras fallo, el reintento o la ejecución en paralelo.

Las actividades comparten un conjunto de parámetros comunes de workflow (about_WorkflowCommonParameters), que sirven para ajustar su comportamiento, la forma de reanudación, la persistencia de estado, etc. Además, Automation permite importar módulos de integración, que no son más que paquetes basados en módulos de PowerShell con sus cmdlets correspondientes.

Como Automation se basa en PowerShell 4.0 con carga automática de módulos, cualquier módulo de integración importado se vuelve accesible desde todos los runbooks sin necesidad de llamar explícitamente a Import-Module. Eso sí, hay que tener en cuenta que los módulos con dependencias externas (registro, rutas no estándar…) pueden necesitar instalación adicional en los servidores Worker para funcionar correctamente.

Si tienes un módulo con muchas dependencias externas, puedes crear un módulo portable usando New-SmaPortableModule. Este proceso genera stubs para cada cmdlet que redirigen la llamada al módulo real instalado en los servidores de trabajo. De este modo, los runbooks pueden descubrir esos cmdlets a efectos de diseño y autocompletado, aunque la lógica real viva fuera.

  Cómo configurar políticas de grupo (GPO) en Windows: todo lo que necesitas saber

Ejecución paralela en flujos de trabajo PowerShell

Una de las ventajas estrella de los workflows es la capacidad de ejecutar comandos en paralelo de forma declarativa. En vez de montar a mano estructuras complejas de runspaces, puedes usar bloques Parallel y ForEach -Parallel, lo que encaja de maravilla para orquestar tareas largas en muchos servidores.

Con la palabra clave Parallel creas un bloque de comandos que se ejecutan simultáneamente. Puedes colocar varias actividades dentro, y todas se iniciarán al mismo tiempo. Una vez que terminen, el flujo continúa con las siguientes actividades fuera del bloque. Esto es ideal para lanzar acciones costosas en varios recursos sin que se bloqueen mutuamente.

Con la construcción ForEach -Parallel procesas en paralelo los elementos de una colección. Cada elemento tiene su propia instancia de las actividades dentro del bloque, que se ejecutan en paralelo entre sí pero de forma secuencial dentro de cada elemento. Este patrón es perfecto para aplicar el mismo procedimiento (por ejemplo, parches y reboot) a un conjunto grande de servidores simultáneamente.

Además, puedes usar la palabra clave Sequence para agrupar comandos secuenciales dentro de un bloque Parallel. De este modo, varias secuencias completas pueden ejecutar en paralelo entre sí, garantizando que la lógica interna de cada secuencia se respeta mientras se aprovecha el paralelismo global en el runbook.

Puntos de control y suspensión de runbooks

Otra funcionalidad clave de los workflows es la de puntos de control (checkpoints). Un checkpoint es como una fotografía del estado actual del flujo de trabajo: valores de variables, progreso y cualquier salida generada hasta ese punto. Se almacena en la base de datos de Automation y permite retomar la ejecución donde se dejó si algo falla.

Para crear un punto de control se utiliza la actividad Checkpoint-Workflow. En el momento en que se ejecuta, se guarda el estado. Si el runbook sufre un error más adelante y se reanuda, arrancará desde el último punto de control completado, evitando repetir trabajo que ya se hizo correctamente.

En escenarios donde una actividad puede fallar pero es seguro y deseable repetirla en caso de fallo (por ejemplo, un intento de creación de máquina virtual), conviene situar checkpoints antes y después de esos comandos críticos. Si la creación falla, el runbook puede repetir ese tramo; si tiene éxito y el fallo se produce posteriormente, el proceso no volverá a crear el recurso de nuevo.

También puedes forzar de manera explícita la suspensión de un runbook con Suspend-Workflow. Esta actividad establece automáticamente un punto de control y detiene el flujo inmediatamente, permitiendo, por ejemplo, que se ejecute una acción manual entre dos fases de automatización. Más tarde, un operador reanuda el runbook desde ese punto exacto.

InlineScript: cuando necesitas PowerShell “puro” dentro de un workflow

La actividad InlineScript te permite ejecutar un bloque de código PowerShell “normal” dentro de un flujo de trabajo, en una sesión independiente que no está regida por Workflow Foundation. Es muy útil cuando necesitas usar cmdlets no soportados directamente como actividades, o cuando una acción solo se puede ejecutar localmente en un determinado equipo.

InlineScript acepta los parámetros comunes de workflow como PSComputerName y PSCredential, de modo que puedes enviar su bloque a otro equipo remoto con credenciales específicas. El patrón típico consiste en recuperar una conexión o credencial de Automation, construir un objeto PSCredential y pasar esos datos a InlineScript para ejecutar comandos en el host de destino.

Hay, sin embargo, varias limitaciones a tener en cuenta: no puedes establecer puntos de control dentro de InlineScript, por lo que si algo falla dentro, al reanudar el workflow se repetirá el bloque desde el principio. Además, mantener InlineScript activo durante mucho tiempo impacta en la escalabilidad, ya que consume una sesión de PowerShell mientras dura su ejecución.

En el interior de InlineScript tampoco están disponibles directamente algunas actividades de Automation como Get-AutomationVariable o Get-AutomationPSCredential. Para pasar datos generados fuera de InlineScript al interior del bloque se usa el modificador de ámbito $Using (por ejemplo, $using:miVariable), y para recuperar datos de salida se asigna el resultado del InlineScript a una variable en el flujo de trabajo.

La recomendación general es minimizar el ámbito de InlineScript: mover bucles for/foreach fuera de él, no definir workflows dentro de estos bloques y limitar InlineScript a trozos de lógica concreta que sí requieren ejecución “pura” de PowerShell. De este modo, se mantiene la capacidad de reanudación y paralelismo del workflow sin sobrecargar el sistema.

Combinando de forma inteligente jobs, runspaces (y sus pools), scripts masivos con Configuration Manager y flujos de trabajo o runbooks de Automation, puedes construir una estrategia sólida de orquestación multi-máquina con PowerShell que escale sin problemas, aproveche el paralelismo de forma controlada y sea capaz de recuperarse de errores sin perder el estado ni duplicar trabajo, tanto en entornos on-premises como en la nube híbrida con Azure Arc.

trucos para mejorar la experiencia de windows terminal
Artículo relacionado:
Trucos avanzados para mejorar la experiencia en Windows Terminal