1

Racking my brains here, and i'm sure it's something simple.

I've built this simple form app that runs an exe in cmd.

The problem is when i click the build iso button the function runs but only outputs the first line of the .exe and the rest of the output is passed to the terminal and not in the textbox?.

It's almost as if the textbox won't accept more than one line, even though i have multiline set to $true?

The yellow text in terminal should be in the textbox as well:

exe Output

Code:

Function xiso_build {

    Set-Location -Path $PSScriptRoot # change to root folder of this script wherever it's run from
    $outputbox.text = & .\extract-xiso.exe -r $selected_file | out-string

  }

# Output of xtract-iso textbox

$global:outputBox = New-Object System.Windows.Forms.TextBox #creating the text box
$outputBox.Location = '10,150' #location of the text box (px) in relation to the primary window's edges (length, height)
$outputBox.Size = New-Object System.Drawing.Size(565,200) #the size in px of the text box (length, height)
$outputBox.MultiLine = $True #declaring the text box as multi-line
$outputBox.ScrollBars = "Vertical" #adding scroll bars if required
$form.Controls.Add($outputBox) #activating the text box inside the primary window



# Build Iso Button

$build_button = New-Object System.Windows.Forms.button
$build_button.Text = 'Build ISO'
$build_button.Size = '200,50'
$build_button.Location = '10,360'
# $button.Anchor = 'Bottom,left' # uncomment to move button down to bottom left of app window
$form.Controls.Add($build_button)
$build_button.Add_Click({xiso_build }) # run 'xiso_build' func from above




I'm at a loss here as to have all output in textbox. Thanks all

Mofi
  • 46,139
  • 17
  • 80
  • 143
bully79
  • 23
  • 4
  • 2
    You could try redirecting output from STDERR: `& .\extract-xiso.exe -r $selected_file 2>&1 | Out-String` – Theo Nov 12 '22 at 12:51
  • You need to send the strings to the instance of the form. You are missing the code that adds the textbox to the form. See https://www.techotopia.com/index.php/Creating_GUIs_in_Windows_PowerShell_1.0_with_WinForms This line need changes $global:outputBox = New-Object System.Windows.Forms.TextBox Global is not the form. – jdweng Nov 12 '22 at 15:34
  • As an aside: Using the `$global:` scope is best avoided, because global variables linger even after the script exits (they are _session_-global). In a script file (`.ps1`), you can define variables directly in the script's scope (the top-level scope) and refer to them from child scopes (e.g. in functions) via the `$script:` scope specifier (if you only need to _read_ such variables, you don't even need that; for a summary of how PowerShell variable scopes work, see the bottom section of [this answer](https://stackoverflow.com/a/36347515/45375)). – mklement0 Nov 12 '22 at 21:06
  • @jdweng, (sorry, reposting due to a typo): the code to add the text box to the form _is_ there: `$form.Controls.Add($outputBox)`. The only problem is that _stderr_ output isn't being captured. – mklement0 Nov 12 '22 at 21:42

1 Answers1

0

Theo has provided the crucial pointer: In order to capture all output from an external program, you must also capture its stderr output - by default, only stdout output is captured by PowerShell.

To that end:

  • use redirection 2>&1 to merge stderr output into the success output stream.

  • convert all input lines to strings with ForEach-Object ToString (which calls the .ToString() method on each line).

    • This is necessary, because PowerShell wraps stderr lines in System.Management.Automation.ErrorRecord instances, which Out-String renders as if they were PowerShell errors. Strictly speaking, you only need this in Windows PowerShell; in PowerShell (Core) 7+, even though the wrapping still happens, rendering is by the wrapped line only.
  • then pipe to Out-String to form a single, multi-line string from all input lines.

$outputbox.text = & .\extract-xiso.exe -r $selected_file 2>&1 |
                  ForEach-Object ToString | # no longer needed in PS 7+
                  Out-String

A more concise alternative with a [string[]] cast and the -join operator:

# [string[]] is no longer needed in PS 7+
$outputbox.text =
  [string[]] (& .\extract-xiso.exe -r $selected_file 2>&1) -join "`n"

Again, the [string[]] cast isn't needed in PowerShell (Core) 7+ anymore (analogous to how ForEach-Object ToString isn't needed anymore above).

The above doesn't add a trailing newline to the result (though you could achieve that with (... -join "`n") + "`n"), whereas Out-String invariably does.[1]


[1] Arguably, Out-String should not do that; see GitHub issue #14444 for a discussion.

mklement0
  • 382,024
  • 64
  • 607
  • 775