Como hacer un Script Multi Thread

Buenas, en este post vamos a detallar como hacer un script principal que pueda lanzar a la vez varias instancias o scripts. Quien no se ha encontrado al hacer un script la necesidad de mejorar los tiempos de ejecución? Pues a continuación voy a detallar una buena forma de hacerlo y que a mi me ha sido muy útil. Es importante tener en cuenta, que por cada hilo (Thread) que lancemos será una nueva instancia de Powershell, por lo que debemos de tener en cuenta no colapsar la máquina desde la que la cual lanzamos el script, ya que supondrá un incremento de consumo de CPU, RAM, Disco, etc.

Para poder lanzar varios hilos dentro de un script utilizaremos el cmdlet “Start-Job”. Debemos de tener varios aspectos claros. Para utilizar Start-Job, tenemos dos opciones para pasar la acción (Script o Bloque). Podemos pasar al cmdlet, los siguientes parámetros -ScriptBlock o -FilePath .

En primer lugar, tenemos que tener muy claro, que las variables globales que tenemos en el Script Principal, no serán visibles por los scripts o bloques de acciones que lancemos. Por lo que si necesitamos información desde el script principal, deberemos de pasarlos en la llamada a Start-Job, con el parámetro –InputObject. Debemos de tenerlo claro, ya que si queremos que tenga disponible módulos de PS, conexión a Virtual Center o lo que queramos, debemos de especificarlo dentro del script o del ScriptBlock.

En el caso de ScriptBlock, pasaremos el bloque de instrucciones que queremos que haga el Job. Se incluiran entre “{ ACCIONES }”.

 
Start-Job -Name "Thread1" -ScriptBlock {Write-Host "Acciones ScriptBlock1"}

En el caso de FilePath, pasaremos la ruta absoluta del script que queremos que haga el Job. 

 
Start-Job -Name "Thread1" -FilePath 'C:\MisScripts\Thread1.ps1' 

Ahora bien, como he dicho antes, como hacemos posible el que tanto el ScriptBlock, como el FilePath acepte parámetros y pueda recoger información del Script Principal? Pues bien, para ello, he dicho que utilizaremos el parámetro -InputObject en la llamada a Start-Job. Y entre “{ }”, pasaremos las variables. Posteriormente en el Script o ScriptBlock tendremos que recoger los parámetros pasados. Vamos a ver un ejemplo de como lanzar una conexión contra Virtual Center.

Script Principal

 
# Script Principal
$USER='usuario'
$PASS='mypassword'
$VCENTER='virtual_center_srv.dominio.net'
Start-Job -Name "Thread1" -InputObject @($USER,$PASS,$VCENTER) -FilePath 'C:\MisScripts\Connect_VIC.ps1' 

Script Thread

 
# Script Connect_VIC.ps1
# Get the Global Vars
$data = $input.getEnumerator()
# Sabemos que en la posición 0 (USER), posición 1 (PASS), posición 2 (VCENTER)
$connection = Connect-VIServer -Server $data[2] -Username $data[0] -Password $data[1]
Write-Host "Conectado a $connection"

Si aplicamos tal cual? Funcionará? Pues probablemente no, como he dicho antes, no es posible compartir la información del script principal y el script thread. En este caso, tendríamos problemas debido al módulo que incluye el cmdlet.

Bien, llegados a este punto, como podemos controlar que los X Threads que lancemos terminen de manera correcta? Pues bien, utilizaremos variables para asignarles la instrucción de Start-Job y posteriormente recogeremos el estado con .JobStateInfo.State. Por lo que haciendo un bucle con el estado de los Jobs, podremos tener controlado, cuando termina. Una vez terminado podemos tener la salida que ofrece cada Thread lanzado, a través de Receive-Job pasando como parámetro -Job el job id.

# Script MAIN
 
# Declaramos las variables globales del Script Principal
$USER='usuario' $PASS='mypassword' $VCENTER='virtual_center_srv.dominio.net'

# Lanzamos los Threads 
$Thread1= Start-Job -InputObject @($USER,$PASS,$VCENTER) -FilePath 'C:\MisScripts\Thread1.ps1' 
$Thread2= Start-Job -InputObject @($USER,$PASS,$VCENTER) -FilePath 'C:\MisScripts\Thread2.ps1'

# Controlar el estado de los Threads para conocer cuando terminan while($Thread1.JobStateInfo.State -ne "Completed" -and $Thread2.JobStateInfo.State -ne "Completed") 
{ 
      $Thread1.JobStateInfo.State 
      $Thread2.JobStateInfo.State 
      Start-Sleep 5 
} 
$Salida_Thread1 = Receive-Job -Job $Thread1 
$Salida_Thread2 = Receive-Job -Job $Thread2 

Bueno, ahora con todos los conceptos claros, voy a poner un ejemplo, de como sacar un listado de las máquinas virtuales con snapshot del Virtual Center y un get-view de todas las máquinas del Virtual Center.

# Script MAIN
 
# Declaramos las variables globales del Script Principal
$USER='usuario' $PASS='mypassword' $VCENTER='virtual_center_srv.dominio.net'

# Lanzamos los Threads 
$Get_VM_SNAPSHOT= Start-Job -InputObject @($USER,$PASS,$VCENTER) -FilePath 'C:\MisScripts\Get_VMs_Snapshots.ps1' 
$Get_VM_VIEW= Start-Job -InputObject @($USER,$PASS,$VCENTER) -FilePath 'C:\MisScripts\Get_VMs_View.ps1'

# Controlar el estado de los Threads para conocer cuando terminan while($Get_VM_SNAPSHOT.JobStateInfo.State -ne "Completed" -and $Get_VM_VIEW.JobStateInfo.State -ne "Completed") 
{ 
 $Get_VM_SNAPSHOT.JobStateInfo.State 
 $Get_VM_VIEW.JobStateInfo.State 
 Start-Sleep 5 
} 
$Get_VM_SNAPSHOT = Receive-Job -Job $Thread1 
$Get_VM_VIEW = Receive-Job -Job $Thread2 

 

# Script Get_VMs_View.ps1

# Función para cargar los módulos necesarios
# Debemos recordar que aunque carguemos módulos en el Script Principal, no estarán disponibles en el script lanzado por Start-Job
Function Importa-Modulos()
{
      Import-Module -Name VMware.VimAutomation.Core -Force
      # Listado de Módulos necesarios, en este caso no necesitamos más.
}

# Recogida de Parámetros pasados
$data = $input.getEnumerator()

# Sabemos que en la posición 0 (USER), posición 1 (PASS), posición 2 (VCENTER)

# Llamamos a la función para importar los módulos de cmdlet
Importa-Modulos
# Conexión al Virtual Center
$connection = Connect-VIServer -Server $data[2] -Username $data[0] -Password $data[1] | out-null

# Declaramos e iniciamos el String Array

$List_VMs_View = Get-VM | Get-View

# Sacamos por pantalla el View de las máquinas

Write-Host "$List_VMs_View"

 

# Script Get_VMs_Snapshots.ps1

# Recogida de Parámetros pasados
$data = $input.getEnumerator()

# Función para cargar los módulos necesarios # Debemos recordar que aunque carguemos módulos en el Script Principal, no estarán disponibles en el script lanzado por Start-Job 
Function Importa-Modulos() 
{ 
    Import-Module -Name VMware.VimAutomation.Core -Force 
    # Listado de Módulos necesarios, en este caso no necesitamos más. 
}

# Sabemos que en la posición 0 (USER), posición 1 (PASS), posición 2 (VCENTER)

# Llamamos a la función para importar los módulos de cmdlet
Importa-Modulos
# Conexión al Virtual Center
$connection = Connect-VIServer -Server $data[2] -Username $data[0] -Password $data[1] | out-null

# Declaramos e iniciamos el String Array

$List_VMs_Snapshots = Get-VM | Get-Snapshot

# Sacamos por pantalla el View de las máquinas

Write-Host "$List_VMs_Snapshots"

 

Bueno, espero que os haya gustado y os sea tan útil como a mi. Muchas gracias por compartir 🙂

 



	

2 comments

Leave a Reply

Your email address will not be published. Required fields are marked *