PowerShell でコマンドを並列実行する

Marion Paul Kenneth Mendoza 2023年6月21日
  1. Windows PowerShell マルチスレッド
  2. PSJob によるスクリプトの並列実行
  3. 私たちの仕事を追跡する
  4. ジョブ出力の取得
  5. スケジュールされたジョブの作成
PowerShell でコマンドを並列実行する

デフォルトの PowerShell セッションはシングルスレッドです。 1つのコマンドを実行し、次のコマンドに移動します。

この方法は、すべてを反復可能に保ち、多くのリソースを使用しないため、優れています。 その場合は、マルチスレッドについて考え始めるときです。

この記事では、さまざまな PowerShell マルチスレッド手法を理解して使用し、複数のデータ ストリームを同時に処理しながら同じコンソールで管理する方法を説明します。

Windows PowerShell マルチスレッド

マルチスレッドは、一度に複数のコマンドを実行する方法です。 PowerShell は通常、単一のスレッドを使用します。 スクリプトを並列化するために複数の方法を使用する方法はたくさんあります。

マルチスレッドの主な目的は、コードの実行時間を短縮することです。 この時間の短縮は、より高い処理能力要件とのトレードオフです。

さらに、マルチスレッドでは多くのアクションが一度に実行されるため、より多くのシステム リソースが必要になります。

完全なスケーリングは見られないことに注意してください。 スクリプト内のアイテムのスピンアップとティアダウンには、しばらく時間がかかります。

PowerShell は、単一のスレッドを使用してコードを実行する必要があり、これで完了です。 コンソールの実行に使用された元のスレッドを使用して、複数のスレッドを持つ他のスレッドを管理します。

その元のスレッドは、他のすべてのスレッドを維持しながら、特定の時点で最大になります。

PSJob によるスクリプトの並列実行

スクリプトをマルチスレッド化する最も便利な方法の 1つは、PSJobs を使用することです。 PSJobs には、Microsoft.PowerShell.Core モジュールに組み込まれたコマンドレットがあります。

Microsoft.PowerShell.Core モジュールは、バージョン 3 以降の PowerShell のすべてのバージョンに含まれています。このモジュールのコマンドを使用すると、フォアグラウンドで別のコードを実行し続けながら、バックグラウンドでコードを実行できます。

Get-Command *-Job

私たちの仕事を追跡する

以下に、ジョブが取り得る最も一般的な状態のリストを示します。

  1. Completed – ジョブが終了しました。出力データを取得するか、ジョブを削除できます。
  2. 実行中 – ジョブは実行中であり、ジョブを強制的に停止しないと削除できません。 出力を取得できません。
  3. Blocked – ジョブはまだ実行中ですが、ユーザーは実行を続行する前に追加情報の入力を求められています。
  4. Failed – ジョブの実行中にスローされた終了エラーが発生しました。

Get-Job コマンドを使用して、開始されたジョブのステータスとジョブのすべての属性を取得します。 状態を確認できるジョブの出力は Running です。

以下の例では、Start-Job コマンドを使用して、予定内で Start-Sleep 5 コードを実行します。 そのジョブのステータスは、Get-Job コマンドを使用して返されます。

コード例:

Start-Job -Scriptblock {Start-Sleep 5}
Get-Job

出力:

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
1      Job1            BackgroundJob   Running       True            localhost            Start-Sleep 5

ジョブ出力の取得

ジョブ内のコードが出力を返す場合があります。 Receive-Job コマンドを使用してそのコードを取得できます。

PSJob を入力として受け取り、ジョブの作業をコンソールに書き込みます。 ジョブの実行中に発生したものはすべて保存されています。

ジョブが取得されると、保存されたすべての内容が表示されます。

この例は、以下のスクリプトを実行することです。 このスクリプトは、ジョブを作成して開始し、Hello World 文字列を出力に書き込みます。

次に、ジョブから出力を取得し、コンソールに表示します。

コード例:

$Job = Start-Job -ScriptBlock {Write-Output 'Hello World'}
Receive-Job $Job

出力:

Hello World

スケジュールされたジョブの作成

PSJobs を操作するもう 1つの方法は、スケジュールされたジョブを使用することです。 これは、タスク スケジューラで構成できる Windows のスケジュールされたタスクに似ています。

スケジュールされた予定は、スケジュールされたタスクで複雑な PowerShell スクリプト ブロックを簡単にスケジュールする方法を作成します。 次に、トリガーに基づいてバックグラウンドで PSJob を実行できます。

ジョブトリガー

ジョブのトリガーは、ユーザーがログオンしたとき、システムが起動したときなど、特定の時間にすることができます。 トリガーを一定間隔で繰り返すこともできます。

これらのトリガーは、スケジュールされたジョブを実行するトリガーを指定する New-JobTrigger コマンドで定義されます。

PSJob トリガーを使用することに加えて、通常の PSJob で使用されるようなスクリプト ブロックを使用します。 トリガーとスクリプト ブロックの両方を取得したら、次のセクションで示すように、Register-ScheduledJob コマンドを使用してジョブを作成します。

このコマンドは、実行されるスクリプト ブロックや、New-JobTrigger コマンドで作成されたトリガーなど、スケジュールされたジョブの属性を指定します。

おそらく、誰かがコンピューターにログインするたびに実行する PowerShell コードが必要になるでしょう。 このためにスケジュールされたジョブを作成できます。

最初に New-JobTrigger を使用してトリガーを定義し、以下に示すようにスケジュールされたジョブを指定します。 以下のスケジュールされたジョブは、誰かがシステムにログインするたびにログ ファイルに行を書き込みます。

コード例:

$Trigger = New-JobTrigger -AtLogon
$Script = {"User $env:USERNAME logged at $(Get-Date -Format 'y-M-d H:mm:ss')" | Out-File -FilePath C:\Temp\User_Login.log -Append}

Register-ScheduledJob -Name Login_Log -ScriptBlock $Script -Trigger $Trigger

出力:

Id         Name            JobTriggers     Command                                  Enabled   
--         ----            -----------     -------                                  -------   
1          Login_Log       1               "User $env:USERNAME logged at $(Ge... True

上記のコマンドを実行すると、ID、スクリプト ブロック、およびその他の属性を表示する新しいジョブを実行する場合と同様の結果が得られます。

AsJob パラメータを使用する

ジョブのもう 1つの用途は、多くの PowerShell コマンドに組み込まれている -AsJob パラメーターです。 さまざまなコマンドがあるため、Get-Command を使用してそれらすべてを見つけることができます。

Get-Command -ParameterName AsJob

最も一般的なコマンドレットの 1つは、Invoke-Command です。 通常、このコマンドを実行すると、すぐにコマンドの実行が開始されます。

ただし、一部のコマンドはすぐに返され、実行していたことを続行できるようになりますが、コマンドレットが終了するまで待機するコマンドもあります。

ほとんどの場合、ローカル マシンで AsJob パラメーターを使用できますが、Invoke-Command コマンドレットには、ローカル マシンで実行するためのネイティブ オプションがありません。 ただし、ComputerName パラメータ値として Localhost を使用することによる回避策があります。

例:

Invoke-Command -ScriptBlock {Start-Sleep 5} -ComputerName localhost

以下のスクリプトは、Invoke-Command コマンドレットを使用して 5 秒間スリープし、AsJob パラメーターを使用して同じコマンドを繰り返し、実行時間の違いを示します。

コード例:

Measure-Command {Invoke-Command -ScriptBlock {Start-Sleep 5}}
Measure-Command {Invoke-Command -ScriptBlock {Start-Sleep 5} -AsJob -ComputerName localhost}

出力:

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 5
Milliseconds      : 20
Ticks             : 50206571
TotalDays         : 5.81094571759259E-05
TotalHours        : 0.00139462697222222
TotalMinutes      : 0.0836776183333333
TotalSeconds      : 5.0206571
TotalMilliseconds : 5020.6571

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 36
Ticks             : 365754
TotalDays         : 4.23326388888889E-07
TotalHours        : 1.01598333333333E-05
TotalMinutes      : 0.00060959
TotalSeconds      : 0.0365754
TotalMilliseconds : 36.5754
Marion Paul Kenneth Mendoza avatar Marion Paul Kenneth Mendoza avatar

Marion specializes in anything Microsoft-related and always tries to work and apply code in an IT infrastructure.

LinkedIn