2

I've got a Powershell script that is making use of Invoke-Command. Here's the code that is being invoked:

$scriptblock = {
  $process = New-Object system.Diagnostics.Process

  $si = New-Object System.Diagnostics.ProcessStartInfo
  $si.FileName = $cmd
  $si.Arguments = $cmd_args
  $si.UseShellExecute = false
  $si.RedirectStandardOutput = true

  $process.StartInfo = $si
  $process.Start()
  $processId = $process.Id
  $process.WaitForExit()
}

Invoke-Command -ScriptBlock $scriptblock

The issue is related to getting the process's standard output to display to the PowerShell console, when the script is run from the PowerShell window.

Now, I am certain that the executable $cmd emits to stdout as when I run the executable with cmd.exe it shows output to that console. I've also been able to successfully redirect the output when I call this Powershell script from a NodeJS script like so:

var exec  = require('child_process').exec,
var cmd   = 'powershell -ExecutionPolicy Bypass "' + launch_cmd + " \'" + ver + "\'\"";

console.log("\n\tUsing command for NodeJS child process:\n\t\t" + cmd + "\n\n")
child = exec(cmd, { cwd : prj }, function(stdout, stderr){});

child.stdout.on("data",function(data){
    process.stdout.write(data);
});

child.stderr.on("data",function(data){
    process.stderr.write(data);
});

child.on("exit",function(){
    console.log("\n\nFinished Process");
});

I want to be able to get the StandardOutput to the PowerShell console. I reviewed this TechNet documentation and tried the following in the script block, but to no avail:

$scriptblock = {
  $process = New-Object system.Diagnostics.Process

  $si = New-Object System.Diagnostics.ProcessStartInfo
  $si.FileName = $cmd
  $si.Arguments = $cmd_args
  $si.UseShellExecute = false
  $si.RedirectStandardOutput = true

  $process.StartInfo = $si
  $process.Start()
  $process.BeginOutputReadLine()
  $process.StandardOutput.ReadToEnd()
  $processId = $process.Id
  $process.StandardOutput
  $process.WaitForExit()
}

Invoke-Command -ScriptBlock $scriptblock

Any suggestions as to how I can make the process display its standard output to the PowerShell console?

ariestav
  • 2,799
  • 4
  • 28
  • 56
  • You have to assign a streamreader to $process.StandardOutput as the technet you linked shows. This page: https://stackoverflow.com/questions/8761888/powershell-capturing-standard-out-and-error-with-start-process says you can do this: $stdout = $p.StandardOutput.ReadToEnd() $stderr = $p.StandardError.ReadToEnd() – Quantic Feb 23 '16 at 21:11

1 Answers1

3

You need to continously read the StandardOutput stream until the process exits to get everything:

$scriptblock = {

    param($cmd, $cmd_args)

    $process = New-Object system.Diagnostics.Process

    $si = New-Object System.Diagnostics.ProcessStartInfo
    $si.FileName = $cmd
    $si.Arguments = $cmd_args
    $si.UseShellExecute = $false
    $si.RedirectStandardOutput = $true

    $process.StartInfo = $si
    $process.Start() | Out-Null

    do{ # Keep redirecting output until process exits
        Write-Host $process.StandardOutput.ReadLine()
    } until ($process.HasExited)
}

Invoke-Command -ScriptBlock $scriptblock -ArgumentList "cmd.exe","/c echo test1 & echo test2 & ping 127.0.0.1 -n 3 > nul & echo test3"

You'll see that the output stream is replicated to your host in real-time. You could also use Write-Output if you're interested in passing the results into a pipeline

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • Beautiful! Thank you so much, Mathias. Your code solved the issue perfectly. I guess my question now is why was Node able to display the output but Powershell couldn't? – ariestav Feb 23 '16 at 21:51
  • 1
    Because you actively subscribe to the "data" event on the streams in the nodejs sample. You could do the same in PowerShell, but I think for 95% of use cases, this method (`do{}until($process.HasExited)`) is probably sufficient (not to mention simpler and cleaner) :) – Mathias R. Jessen Feb 23 '16 at 21:54