1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PowerShellで外部ファイルを非同期実行する

Last updated at Posted at 2022-06-09

背景

既存のexeファイルをマルチプロセスで実行したいと思い、PowerShellで実装できたので備忘のために記載します。
PowerShell 7 Preview.3というバージョンなら、ForEach-Objectの新機能である「ForEach-Object -Parallel」を使えるのですが、会社PCのPowerShellバージョンが5.1だったので、泣く泣く断念しました。

ForEach-Object -Parallelの詳細については以下サイトがとても参考になります。
[PowerShell] ForEach-Objectの新機能、ForEach-Object -Parallel について

実装

サンプルとして、指定した時間待機をした後に、メッセージダイアログを表示するexeファイルを用意しました。

batファイル
@echo off
setlocal enabledelayexpansion

powershell -ExecutionPolicy Bypass -command MultiProcess.ps1

endlocal
pause
ps1ファイル

# 非同期処理の関数
function ParallelForEach-Object
{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory=$true, Position=1)][int]$para_num,         # 同時実行数
    [Parameter(Mandatory=$true, Position=2)][string]$process_name,  # プロセス名
    [Parameter(Mandatory=$true, Position=3)][scriptblock]$process,  # プロセススクリプトブロック
    [scriptblock]$begin={}, # ループの一番最初に実施したい処理のスクリプトブロック(今回は未指定です)
    [scriptblock]$end={},   # ループの一番最後に実施したい処理のスクリプトブロック(今回は未指定です)
    [Parameter(ValueFromPipeline=$true)][psobject]$inputObject  # パイプライン処理用のオブジェクト
  )
  begin
  {
    &$begin
    $jobs=@()
  }

  process
  {
    $jobs | Receive-Job

    while(@(Get-Process | ?{$_.ProcessName -eq $process_name})).Length -ge $para_num)
    {
      $jobs | Receive-Job
      start-sleep -Milliseconds 100
    }

    $jobs += Start-Job $process -argumentList $inputObject
    start-sleep -Milliseconds 2000
  }
  end
  {
    while(@(Get-Process | ?{$_.ProcessName -eq $process_name})).Length -ge 0)
    {
      $jobs | Receive-Job
      start-sleep -Milliseconds 100
    }
    $jobs | Receive-Job
    $jobs | remove-Job
    &$end
  }
}

$exePath = "c:\ConsoleApp3.exe"
$processName = [System.IO.Path]::GetFileNameWithoutExtension($exePath)

$objList = @()

# 実行するexeのパスや引数を指定する
# exeの引数として"人名"と"待機時間"を指定しています。
$list = @("Aさん","Bさん","Cさん","Dさん")
$cnt = 40
foreach($name in $list)
{
  $cnt -= 5;
  $objList += [PSCustomObject] @{
    exe = $exePath;
    args = "$name $cnt";
  }
}

# 同時実行数4でexeを起動する
$objList | ParallelForEach-Object 4 $processName {
  Start-Process -FilePath $args[0].exe -ArgumentList $args[0].args
}
実行結果⓵
開始時間:2022/06/09 23:14:38
35秒待機しました。ようこそAさん
終了時間:2022/06/09 23:15:13
実行結果⓶
開始時間:2022/06/09 23:14:40
30秒待機しました。ようこそBさん
終了時間:2022/06/09 23:15:10
実行結果③
開始時間:2022/06/09 23:14:43
25秒待機しました。ようこそCさん
終了時間:2022/06/09 23:15:08
実行結果④
開始時間:2022/06/09 23:14:45
20秒待機しました。ようこそDさん
終了時間:2022/06/09 23:15:05

説明

AさんからDさんの名前を表示するexeを同時実行で呼び出しています。
「Get-Process」メソッドで実行中のプロセス一覧から実行中のexeのプロセス名を確認しており、
そのプロセス名の数が「$para_num」変数で指定した数よりも少なければexeを実行するという仕組みで
同時実行数を制御しています。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?