web-dev-qa-db-ja.com

Invoke-CommandコマンドレットのScriptBlockでエラーを処理する

PowerShellを使用してリモートマシンにサービスをインストールしようとしています。

これまでのところ、私は以下を持っています:

Invoke-Command -ComputerName  $remoteComputerName -ScriptBlock {
         param($password=$password,$username=$username) 
         $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
         $credentials = New-Object System.Management.Automation.PSCredential ($username, $secpasswd)
         New-Service -Name "XXX" -BinaryPathName "c:\XXX.exe" -DisplayName "XXX XXX XXX" -Description "XXXXXX." -Credential $credentials -ErrorVariable errortext 
         Write-Host("Error in: " + $errortext)
        } -ArgumentList $password,$username -ErrorVariable errortext 


Write-Host("Error out: " + $errortext)

New-Serviceの実行中にエラーが発生した場合、$ Errortext ErrorVariableはScriptBlock内で適切に設定されます。

Invoke-CommandのErrorVariableが設定されていません(予想通り)。

私の質問は:

Invoke-CommandのErrorVariableをScriptBlock内で取得したエラーに設定することは、どういうわけか可能ですか?

InstalUtil、WMI、およびSC=を使用してサービスをインストールすることもできますが、現時点では関係ありません。

11
flayn

いいえ、Invoke-Command呼び出しからErrorvariableを取得して、スクリプトブロックと同じように設定することはできません。

しかし、目標が「スクリプトブロック内のエラーを検出して処理し、エラーがInvoke-Command呼び出し元のコンテキストに戻される」場合は、手動で実行してください。

$results = Invoke-Command -ComputerName server.contoso.com -ScriptBlock {
   try
   {
       New-Service -ErrorAction 1
   }
   catch
   {
       <log to file, do cleanup, etc>
       return $_
   }
   <do stuff that should only execute when there are no failures>
}

$resultsにエラー情報が含まれるようになりました。

18
latkin

Invoke-Command引数リストは、一方通行です。スクリプトでエラー変数を出力することもできます。スクリプトブロックの最後の行に次のように記述します。

$errortext

または、それでもなお、-ErrorVariableを使用してエラーをまったくキャプチャしないでください。エラーを含むスクリプトブロックの出力は、リモート接続を介しても呼び出し元に戻ります。

C:\> Invoke-Command -cn localhost { Get-Process xyzzy } -ErrorVariable errmsg 2>$null
C:\> $errmsg
Cannot find a process with the name "xyzzy". Verify the process name and call the cmdlet again.
    + CategoryInfo          : ObjectNotFound: (xyzzy:String) [Get-Process], ProcessCommandException
    + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
    + PSComputerName        : localhost

一般に、エラーストリームのエラーを通常の出力とは別にしておく方がはるかに良いと思います。

11
Keith Hill

これはほぼ間違いなく「正しい」答えではありませんが、Invoke-Commandがスクリプトでエラーをスローするようにしたい場合に使用します。

$error.Clear()
Invoke-Command -ComputerName localhost -ScriptBlock {Command-ThatFails}
$if ($error.Count -gt 0) { throw $error[0] }

エラーを変数に保持したい場合は、次のようにします。

$error.Clear()
Invoke-Command -ComputerName localhost -ScriptBlock {Command-ThatFails}
$if ($error.Count -gt 0) { $myErrorVariable = $error[0] }
0
Adam S

厳密には、答えはノーだと思います。スクリプトブロック内で、Invoke-CommandのErrorVariableをErrorVariableの内容に設定することはできません。 ErrorVariableは、それがアタッチされているコマンド専用です。

ただし、スクリプトブロックの変数をInvoke-Commandのスコープに渡すことができます。コードでは、_-ErrorVariable errortext_を使用してNew-Serviceコマンドを実行します。代わりに、_-ErrorVariable script:errortext_のように、変数名の前に「script:」を付けて、変数を「script」スコープに作成します。これにより、変数はスクリプトブロックの外部だけでなく内部でも使用できるようになります。

最後の行Write-Host("Error out: " + $errortext)は、スクリプトブロック内で生成されたエラーを出力します。

詳細情報 here および here

0
Todd Walton