1

For an important data migration, I would like to execute in parallel multiple scripts in side subfolders :

I did not succeed to do this :

$folders = Get-ChildItem -Directory

foreach($folder in $folders){
    $cmd = "powershell '$folder\script.ps1'"
    $job = start-job -ScriptBlock {Invoke-Expression $cmd}
}

folder estructure

Thank you for your help!

Victor Silva
  • 723
  • 4
  • 17

4 Answers4

2

Multithreaded in powershell 7:

Get-ChildItem -Directory | foreach-object -parallel {
  & $_\script.ps1
}
js2010
  • 23,033
  • 6
  • 64
  • 66
1

js2010's answer is the simplest and best solution for PowerShell (Core) 7+, where ForEach-Object now has a -Parallel parameter for running script blocks in parallel threads.


A solution for Windows PowerShell - the legacy PowerShell edition whose latest and last version is v5.1:

Get-ChildItem -Directory |
 ForEach-Object {
   Start-Job { Set-Location -LiteralPath ($using:_).FullName; .\script.ps1 }
 } |
 Receive-Job -Wait -AutoRemoveJob

Note:

  • If the script needn't be run with its own directory as the working dir., the following Start-Job call will do:

    Start-Job { & (Join-Path ($using:_).FullName script.ps1) }
    
  • If installing a module on demand is an option, consider installing the ThreadJob module, whose Start-ThreadJob offers a thread-based and therefore faster and more lightweight alternative to the slow and resource-intensive child-process-based background jobs that Start-Job creates.

    • Once installed, you can simply substitute Start-ThreadJob for Start-Job in the code above, given that Start-ThreadJob is compatible with all job-related cmdlets, such as Receive-Job.

    • Note that PowerShell (Core) 7+ comes with Start-ThreadJob, though the ForEach-Object -Parallel option - built on the same thread-based infrastructure - is often the simpler choice.

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

You can use Invoke-Command for concurrent processing. Here's an example that may meet your requirements.

Get-ChildItem -Directory | ForEach-Object {
    $folderPath = $_.FullName
    Start-Job -ScriptBlock { .\script.ps1 $using:folderPath }
}

Get-Job | ForEach-Object {
    $result = Wait-Job $_ | Receive-Job
    Remove-Job $_
    $result
}
nimrod
  • 102
  • 4
  • 1
    invoke command doesnt invoke in parallel in this answer. only when remoting it does. – Santiago Squarzon May 25 '23 at 13:59
  • 1
    You are right. I will edit the answer. – nimrod May 25 '23 at 14:14
  • Passing the folder path _as an argument_ to each `.\script.ps1` call isn't what the question asks for, and it won't help. Instead, you must make sure that the folder path is incorporated into the path of the `script.ps1` script being invoked. – mklement0 May 27 '23 at 23:00
0

I found a working solution, by using Start-Process, it answer my need. THank you every one