3

I have a script located on a remote system.

On the server "web12" under C:\tmp\hgttg.ps1:

 Write-Host "Don't Panic"
 exit 42

I invoke this script from my local box (both systems running v4.0) using Invoke-Command:

$svr = "web12"
$cmd = "C:\tmp\hgttg.ps1"
$result = Invoke-Command -ComputerName $svr -ScriptBlock {& $using:cmd}

This causes the following output when executed:

> $result = Invoke-Command -ComputerName $svr -ScriptBlock {& $using:cmd}
Don't Panic
> $result
>

($result is not set, output goes straight to the console, no good!) After much web searching and troubleshooting, I have come to some improvement:

> $result = Invoke-Command -ComputerName $svr -ScriptBlock {& $using:cmd; $LASTEXITCODE}
Don't Panic
> $result
42
>

Now I'm able to capture the return code, but the output still goes straight to the console. This is as far as I can get. On the long list of things I have already attempted, none of the following have worked:

  • Instead of '&' used 'Invoke-Expression' with -OutVariable out; New-Object -TypeName PSCustomObject -Property @{code=$LASTEXITCODE; output=$out}

This produces the output:

> $result
code           : 42
output         : 
PSComputerName : web12
RunspaceId     : aaa00a00-d1fa-4dd6-123b-aa00a00000000
> 
  • Attempted both iterations above with '4>&1' and '*>&1' on the end of the inner and outer commands, no change.

  • Attempted each of:

    1. "& $using:cmd | Tee-Object -Variable out; $out"
    2. "& $using:cmd >$out; $out"
    3. "$out = & $using:cmd; $out"

    (Discarding the return code just to get output) Again, no change.

  • Also attempted: '& $using:cmd >> C:\tmp\output.log; $LASTEXITCODE'. The generated file was empty, and the text was still output to the local terminal.

I'm sure there's something obvious that I'm missing, but so far all I've hit are dead ends. Any suggestions?

mklement0
  • 382,024
  • 64
  • 607
  • 775
Derek_6424246
  • 237
  • 3
  • 12
  • 2
    "*I'm sure there's something obvious that I'm missing*" - don't use write-host. The whole point of write-host is that it's not a function return value, it's text written to the host screen. Use Write-Output (or nothing) instead. – TessellatingHeckler Mar 28 '18 at 00:11
  • @TessellatingHeckler The example I used was intentional, the scripts I will actually be calling are putting a lot of info out to the screen, then return an exitcode. I can't change the target scripts, but I still need to see what they write out. – Derek_6424246 Mar 28 '18 at 00:18
  • 2
    If they are native commands (`.exe`s) using stdout then they aren't writing to the screen, and their output should be capturable. If they are PowerShell scripts using `Write-Host` then they are broken and need fixing. If you cannot touch the scripts your only other option is to upgrade your environment to PowerShell 5.1 which can remote the output of `write-host`. If they are `.exe`s writing directly to the console, I don't know if there's anything you can do. – TessellatingHeckler Mar 28 '18 at 00:23

1 Answers1

5

On PSv4- (versions 4.x or below), you simply cannot capture Write-Host output - it invariably goes straight to the console.

In PSv5+, Write-Host (too) writes to the newly introduced information stream that the newly introduced Write-Information cmdlet is designed to write to; its number is 6.

Thus, if your target host runs PSv5+, you can use the following; note how *> captures all output streams by redirecting (&) them to the success stream (1), but you can use 6> to capture the information stream selectively):

$result = Invoke-Command -ComputerName $svr -ScriptBlock {& $using:cmd *>&1; $LASTEXITCODE}
$output = $result[0..($result.Count-2)]
$exitCode = $result[-1]
mklement0
  • 382,024
  • 64
  • 607
  • 775