リモート コンピューターを PowerShell で操作するコマンドレットの1つである「Enter-PSSession」は、PowerShell のリモートデスクトップ版で、操作は対話型処理に限定され、戻り値をこちら側で取得することができません。
この問題を解決するのが「Invoke-Command」です。
Invoke-Command はコマンドやスクリプトをリモート投入し、結果をローカルに返すコマンドレットです。
「リモート投入」なので Enter-PSSession のように対話型処理はできませんが、バッチ処理が可能ですし、戻り値を得られるので、投入したコマンドの結果に応じて処理分岐することが可能です。
事前設定は Enter-PSSession と同じです。
まずは、リモート コンピューター上で dir c:\ を実行して、その結果を受け取ってみましょう。
投入するコマンドを -ScriptBlock で指定し、戻り値を echo してみます。
|
こんな感じで「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 は、単純なコマンドだけではなく関数を投入することが可能です。
|
この関数を投入するには、-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 |
ただし、標準出力をしない関数を同様に配列してして扱うと残念な結果になってしまいます。
|
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 |
めでたしめでたし
[2021年5月23日 追記]
bool 型引数の場合、うまく引数を渡すことが出来ない事があります。
(仕様なのか、別の問題なのかまで調べていないので、あやふやな表現で申し訳ないです)
この場合は、$args 自動変数を使うとうまくいきます。
|
$Result = Invoke-Command TergetServer -ScriptBlock $function:TestFunc02 -ArgumentList "aaa", $true |
PS C:\> $Result = Invoke-Command TergetServer -ScriptBlock
$function:TestFunc02 -ArgumentList "aaa", $true PS C:\> echo $Result 1st Argument : aaa 2ndt Argument : True aaaTrue |
リモートに格納されているスクリプトを起動する場合は、-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)
PowerShell スクリプト引数(Param)の Tips
自動変数について - PowerShell | Microsoft Docs
Copyright © MURA All rights reserved.