Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle errors in ScriptBlock in Invoke-Command Cmdlet

I am trying to install a service on a remote machine using the powershell.

So far I have the following:

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)

When there is an error while executing New-Service the $errortext ErrorVariable get set properly inside the ScriptBlock, because the text: "Error in: shows me the error.

The ErrorVariable of the Invoke-Command does not get set (which I expected).

My question is:

Is it somehow possible to set the ErrorVariable of the Invoke-Command to the error I got inside the ScriptBlock?

I know I could also use InstalUtil, WMI and SC to install the service, but this is not relevant at the moment.

like image 321
flayn Avatar asked Sep 26 '12 11:09

flayn


2 Answers

No, you can't get the Errorvariable from the Invoke-Command call to be set the same as in the scriptblock.

But if your goal is "detect and handle errors in the scriptblock, and also get errors returned back to the context of the Invoke-Command caller" then just do it manually:

$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 now contains the error information.

like image 196
latkin Avatar answered Oct 05 '22 03:10

latkin


The Invoke-Command argument list is a one way deal. You can either output the error variable in the script e.g. on the last line of the scriptblock put:

$errortext

or better yet, just don't capture the error via the -ErrorVariable at all. The scriptblock output, including errors, will flow back to the caller even over a remote connection.

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

In general, I think it is much better to keep errors on the error stream, separated from the normal output.

like image 21
Keith Hill Avatar answered Oct 05 '22 02:10

Keith Hill