Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
多くの方が Windows PowerShell をお使いのことと思います。
PowerShell にはさまざまな「奥義」が存在しますが、「バックグラウンドジョブ」も奥義の一つです。これは究極奥義である「ワークフロージョブ」へとつながる大切な概念です。
まずは以下をご覧ください。
Get-Service -ComputerName Server01
何をやっているかは一目瞭然ですよね。
リモートコンピューター Server01 上のサービス一覧を取得しています。
通常 Get-Service は直ぐに結果を得られるので問題ないのですが、結果取得までに10分とか20分を要する場合にはコンソールを占有されてしまうことを回避するため、「バックグラウンドジョブ」と呼ばれる方法を使用します。
つまり、コマンドを投げっぱなしにしておいて(非同期実行)、あとから結果を取りに行く...という方法です。
バックグラウンドジョブを作成するには2つの方法があります。
- -AsJob パラメタを使用する
- Start-Job コマンドレットを使用する
いずれを使用しても得られる結果は同じですが、コマンドレットによっては -AsJob をサポートしていない場合もあり、その場合には Start-Job の引数にコマンドレットを指定します。
例えば、Get-Service の場合には -AsJob パラメタをサポートしていないため、バックグラウンドジョブ化するには以下のように書きます。
Start-Job -ScriptBlock { Get-Service -ComputerName Server01 }
さて、ここまでは一般ピープルでも知っていることです。
エキスパートな方はここからが重要なのです。
さっそくですが、以下の2つの違いわかりますか?いずれも上の記述を書き換えたもので、同じ結果が得られます。
$S = New-PSSession -ComputerName Server01
Invoke-Command -Session $S -ScriptBlock { Get-Service } -AsJob
$S = New-PSSession -ComputerName Server01
Invoke-Command -Session $S -ScriptBlock {Start-Job -ScriptBlock { Get-Service } }
1 行目の 「$S = New-PSSession -ComputerName Server01 」はおわかりですよね。リモートコンピューター Server01 と PS セッションを張ってます。図にすると以下のような感じです。
問題は2行目です。同じことをやってそうなのですが、微妙に書き方が異なっています。-AsJob と Start-Job に何か秘密が隠れているようではあります。
| Invoke-Command -Session $S -ScriptBlock { Get-Service } -AsJob |
Invoke-Command を使用すると、リモートコンピューター上でコマンドレットを実行することができます。今回の例では、事前に作成した Server01 とのセッションを使い、Server01 上で Get-Service を実行しています。
-AsJob を指定することで Invoke-Command 自体がバックグラウンドジョブ化され、リモートでのコマンド実行を待ち合せることなく、バックグラウンドで非同期に実行することができます。
結果は Invoke-Command を実行したローカルホストに保存されます(ここ重要!)。
図にすると以下のような感じです。
| Invoke-Command -Session $S -ScriptBlock {Start-Job -ScriptBlock {Get-Service}} |
一方、-AsJob ではなく、ScriptBlock 内で Start-Job を実行した場合はどうなるでしょう。
Start-Job は Server01 上で実行されるため、バックグラウンドジョブ化されるのは Server01 上の Get-Service コマンドです。
では、結果はどこに保存されるかといえば、ジョブが実行された Server01 上です。
図にすると以下のようになります。
当然、結果を取りに行くときは、以下のように Server01 に対して Receive-Job する必要があります。
Invoke-Command -Session $S -ScriptBlock { Receive-Job <jobid> }
両者の違いを正しく理解しておくことはとても重要です。
例えば、「長く時間を要するバックグラウンドジョブを実行して、あとで結果を受け取ろう」と考えたとしましょう。
もし Invoke-Command -AsJob を使用してローカルコンピューター上に結果を保存するようにした場合、ローカルコンピューターはジョブが終わるまでネットワークから切り離すこともシャットダウンすることもできません。ネットワークから切り離されたり、シャットダウンした瞬間にジョブは消滅します。
しかし、後者( Invoke-Command {Start-Job })で実行すれば、ジョブはリモートで実行され、結果もリモートに保存されます。
ジョブを投げたあとはDisconnect-PSSession でセッションをいったん切断し、あとから Connect-PSSession でもとのセッションに再接続することができます。
(参考)
【Management】PowerShell V3.0 で向上したリモーティング機能 その1
https://blogs.technet.com/b/junichia/archive/2012/03/24/3488392.aspx【Management】PowerShell V3.0 で向上したリモーティング機能 その2
https://blogs.technet.com/b/junichia/archive/2012/03/26/3488520.aspx
「ジョブの実行場所が、結果の保存場所である」
.....ということをくれぐれも忘れないでください。
