35

My question is very similar to this one, except I'm trying to capture the return code of a ScriptBlock using Invoke-Command (so I can't use the -FilePath option). Here's my code:

Invoke-Command -computername $server {\\fileserver\script.cmd $args} -ArgumentList $args
exit $LASTEXITCODE

The problem is that Invoke-Command doesn't capture the return code of script.cmd, so I have no way of knowing if it failed or not. I need to be able to know if script.cmd failed.

I tried using a New-PSSession as well (which lets me see script.cmd's return code on the remote server) but I can't find any way to pass it back to my calling Powershell script to actually DO anything about the failure.

Community
  • 1
  • 1
Jay Spang
  • 1,903
  • 6
  • 25
  • 32

4 Answers4

43
$remotesession = new-pssession -computername localhost
invoke-command -ScriptBlock { cmd /c exit 2} -Session $remotesession
$remotelastexitcode = invoke-command -ScriptBlock { $lastexitcode} -Session $remotesession
$remotelastexitcode # will return 2 in this example
  1. Create a new session using new-pssession
  2. Invoke your scripblock in this session
  3. Fetch the lastexitcode from this session
jon Z
  • 13,880
  • 1
  • 30
  • 34
  • This worked. I didn't know that you could pass remote variables from a session back to the local script like that. Thanks! – Jay Spang Dec 18 '11 at 19:41
  • 7
    Wouldn't `$remotelastexitcode = invoke-command -ScriptBlock { cmd /c exit 2; $lastexitcode} -Session $remotesession` work? Since you are using the sessions to give multiple commands, you can probably prevent that. – manojlds Dec 19 '11 at 07:16
  • 2
    @manojlds yes, capturing the lastexitcode in the first scriptblock will also work. – jon Z Dec 20 '11 at 10:03
  • would it be possible to retrieve the last exit code from a remote session where the -filepath argument is used eg Invoke-Command -Session $Session -FilePath "FullStopBizTalkApp.ps1" -argumentlist $BizTalkMgmtDBConString, $ApplicationNameInBizTalk – Rob Bowman Sep 17 '12 at 16:47
  • Thanks a lot - that really helped me too! – AllDayPiano Oct 28 '15 at 08:36
  • @jonZ excelent answer! thanks! it helped me a lot! I just like to point out a security suggestion for the guys using this inside any script block: close the session at the end with `remove-pssession $remotesession`! Because usually there is a credential involved... – Beccari Sep 28 '17 at 21:13
7
$script = {
    # Call exe and combine all output streams so nothing is missed
    $output = ping badhostname *>&1

    # Save lastexitcode right after call to exe completes
    $exitCode = $LASTEXITCODE

    # Return the output and the exitcode using a hashtable
    New-Object -TypeName PSCustomObject -Property @{Host=$env:computername; Output=$output; ExitCode=$exitCode}
}

# Capture the results from the remote computers
$results = Invoke-Command -ComputerName host1, host2 -ScriptBlock $script

$results | select Host, Output, ExitCode | Format-List

Host : HOST1
Output : Ping request could not find host badhostname. Please check the name and try again
ExitCode : 1

Host : HOST2
Output : Ping request could not find host badhostname. Please check the name and try again.
ExitCode : 1

Matthew MacFarland
  • 1,495
  • 2
  • 14
  • 23
2

@jon Z's answer is good, but this is simpler:

$remotelastexitcode = invoke-command -computername localhost -ScriptBlock {
    cmd /c exit 2; $lastexitcode}

Of course if your command produces output you'll have to suppress it or parse it to get the exit code, in which case @jon Z's answer may be better.

jimhark
  • 4,613
  • 1
  • 23
  • 26
2

I have been using another method lately to solve this problem. The various outputs that come from the script running on the remote computer are an array.

$result = Invoke-Command -ComputerName SERVER01 -ScriptBlock {
   ping BADHOSTNAME
   $lastexitcode
}

exit $result | Select-Object -Last 1

The $result variable will contain an array of the ping output message and the $lastexitcode. If the exit code from the remote script is output last then it can be fetched from the complete result without parsing.

To get the rest of the output before the exit code it's just:
$result | Select-Object -First $(result.Count-1)

Matthew MacFarland
  • 1,495
  • 2
  • 14
  • 23