Home > Windows にまつわる e.t.c.

リモート コンピューターのバッチ操作(Invoke-Command)


リモート コンピューターを PowerShell で操作するコマンドレットの1つである「Enter-PSSession」は、PowerShell のリモートデスクトップ版で、操作は対話型処理に限定され、戻り値をこちら側で取得することができません。

この問題を解決するのが「Invoke-Command」です。

Invoke-Command はコマンドやスクリプトをリモート投入し、結果をローカルに返すコマンドレットです。

「リモート投入」なので Enter-PSSession のように対話型処理はできませんが、バッチ処理が可能ですし、戻り値を得られるので、投入したコマンドの結果に応じて処理分岐することが可能です。

事前設定は Enter-PSSession と同じです。

 

簡単な使い方

まずは、リモート コンピューター上で dir c:\ を実行して、その結果を受け取ってみましょう。

投入するコマンドを -ScriptBlock で指定し、戻り値を echo してみます。

PS C:\> $Return = Invoke-Command TergetServer -ScriptBlock { dir c:\ }
PS C:\> echo $Return


    ディレクトリ: C:\


Mode                LastWriteTime     Length Name                                  PSComputerName
----                -------------     ------ ----                                  --------------
da---        2014/01/25     14:33            CheckEventLog                         TergetServer
d----        2013/09/12     16:17            inetpub                               TergetServer
d----        2014/12/01     12:08            LogMove                               TergetServer
d----        2013/08/23      0:52            PerfLogs                              TergetServer
d----        2014/12/01     12:14            ping_log                              TergetServer
d-r--        2015/02/15     10:23            Program Files                         TergetServer
d----        2015/02/15     10:23            Program Files (x86)                   TergetServer
d----        2014/12/01     12:10            pSyslog                               TergetServer
d----        2014/10/10     10:21            Tools                                 TergetServer
d-r--        2013/09/12     16:23            Users                                 TergetServer
d----        2015/03/12      4:37            Windows                               TergetServer
d----        2013/09/12     16:15            Windows.old                           TergetServer
d----        2015/03/15     12:32            WindowsUpdate                         TergetServer
d----        2014/12/01     12:04            work                                  TergetServer
d----        2015/03/15     12:25            WU_Log                                TergetServer

 

こんな感じで「dir c:\」がリモート コンピューターで実行され、実行結果がローカル コンピューターに戻り値として帰ってきます。

 

資格情報(アカウント)を指定する

ワークグループ環境等で、アカウントを明示的に指定する場合は、Enter-PSSession と同様に -Credential オプションが使えます。

Invoke-Command TergetServer -Credential TergetServer\administrator -ScriptBlock { dir c:\ }

資格情報は、事前に変数格納することもできるので

$Credential = Get-Credential TergetServer\administrator
Invoke-Command TergetServer -Credential $Credential -ScriptBlock { dir c:\ }

このように資格情報を指定することも出来ます。

 

複数のコマンドを連続して投入する

複数のコマンドを連続投入する場合は、New-PSSession でセッションを事前に取得してコマンド投入することも可能です。

# セッションの取得
$PSSession = New-PSSession TergetServer -Credential TergetServer\administrator

# コマンドの投入
Invoke-Command -Session $PSSession -ScriptBlock { dir c:\ }
Invoke-Command -Session $PSSession -ScriptBlock { dir d:\ }

# セッションの解放
Remove-PSSession $PSSession

 

引数に変数を渡す

引数に変数を使いたいことがあります。

この場合、ミスをしやすいのがこのような使い方です。

×間違いやすい例

$Drive = "C:\"
Invoke-Command TergetServer -ScriptBlock { dir $Drive }

一見正しく動きそうですが、この書き方では引数が渡されません。(引数がセットされず $null が渡されます)

引数を渡すには、組み込み変数である $args 配列を使い、-ArgumentList で引数指定します。

$Drive = "C:\"
Invoke-Command TergetServer -ScriptBlock { dir $args[0] } -ArgumentList $Drive

 

関数の投入と戻り値の受け取り方

Invoke-Command は、単純なコマンドだけではなく関数を投入することが可能です。

function TestFunc( $a, $b ){
    echo "1st Argument : $a"
    echo "2ndt Argument : $b"
    $c = $a + $b
    return $c
}

この関数を投入するには、-ScriptBlock に $function: で関数名を指定し -ArgumentLis で引数を渡しますます。

$Result = Invoke-Command TergetServer -ScriptBlock $function:TestFunc -ArgumentList "aaa", "bbb"

この例の場合は、$Result に echo で標準出力された $a $b と、戻り値である $c が配列に格納されます。

PS C:\> $Result = Invoke-Command TergetServer -ScriptBlock $function:TestFunc -ArgumentList "aaa", "bbb"
PS C:\> echo $Result
1st Argument : aaa
2ndt Argument : bbb
aaabbb

return 値で判定したい場合は、return 値が配列の末尾に格納されているので、配列の末尾だけを取り出します。

PS C:\> $ReturnValuse = $Result[$Result.Length - 1]
PS C:\> echo $ReturnValuse
aaaabbb

 

ただし、標準出力をしない関数を同様に配列してして扱うと残念な結果になってしまいます。

function TestFunc2( $a, $b ){
    $c = $a + $b
    return $c
}

 

PS C:\> $Result = Invoke-Command TergetServer -ScriptBlock $function:TestFunc2 -ArgumentList "aaa", "bbb"
PS C:\> $ReturnValuse = $Result[$Result.Length - 1]
PS C:\> echo $ReturnValuse
b

文字列が文字の配列なので、最後の1文字だけ取り出されてしまいました。

これを避けるには、Invoke-Command の戻り値を配列にキャストします

[array]$Result = Invoke-Command log -ScriptBlock $function:TestFunc2 -ArgumentList "aaaa", "bbb"
または
$Result = @(Invoke-Command TergetServer -ScriptBlock $function:TestFunc2 -ArgumentList "aaaa", "bbb")

 

PS C:\> $Result = @(Invoke-Command TergetServer -ScriptBlock $function:TestFunc2 -ArgumentList "aaaa", "bbb")
PS C:\> $ReturnValuse = $Result[$Result.Length - 1]
PS C:\> echo $ReturnValuse
aaaabbb

めでたしめでたし

 

リモートに格納されているスクリプトを起動する

リモートに格納されているスクリプトを起動する場合は、-ScriptBlock にリモートのスクリプトフルパスを指定します。

Invoke-Command TergetServer -ScriptBlock { c:\Test\submit.ps1 $args[0] } -ArgumentList "aaa"

 

ローカルにあるスクリプトを投入する

先の例だと、実行するスクリプトを事前にリモートコンピューターにコピーしておく必要がありますが、Invoke-Command はスクリプト ファイルをコピーせずリモートコンピューター上で実行することができます。

この場合は、-FilePath に投入するスクリプトのフルバスを指定します。引数は -ArgumentList で渡すことができます。

Invoke-Command TergetServer -FilePath c:\windowsupdate\autowindowsupdate.ps1 -ArgumentList "aaaa"

 

 

Invoke-Command は、 Enter-PSSession に比べて少し複雑ですが、とても強力なリモート操作コマンドレットなので、何かと使い手があります。
まだ使ったことない方は一度お試しあれ !!

 

 

関連情報

リモート コンピューターの対話操作(Enter-PSSession)

リモート コンピューターのパラレル バッチ操作(Invoke-Command -AsJob)

 

back.gif (1980 バイト)

home.gif (1907 バイト)

Copyright © MURA All rights reserved.