1

I have a script to call an API endpoint to retrieve data from a hierarchy in an application.

This hierarchy has a few levels: Campus, Building, Floor To make it user friendly, I've written the script to compile a table which gets the names of the hierarchy level being queried into an array, and adds a number to the entry in a new array column (basically the array index, made human-readable)

The script writes the table to the terminal using a Format-Table command, and then asks the user with a Read-Host command to provide an input based on the prompt provided.

If I then call this script assigning it to a variable (to make the output manipulation easier) the prompt doesn't show, so you can provide values blindly and not achieve what you want.

For example, if I call the script directly I get this in the terminal window:

.\My-script-here.ps1


Number name
------ ----
     1 Campus 1
     2 Campus 2

Enter number of campus:

If I assign it to a variable, I get this:

$variable = .\My-script-here.ps1

Enter number of campus:

Is there a way to get the compiled table to appear when assigning the script to the variable? Currently the line in the script is $Table | Format-Table -Property Number,Name I've tried piping this to Write-Output but that hasn't made a difference

1 Answers1

1

If you want to print the table with proper formatting to the display only, use Out-Host:

A simplified example:

[PSCustomObject]@{
  Foo = 'Bar'
  Baz = 42
} | 
  Format-Table |
  Out-Host

Read-Host 'Enter number of campus'

The above prints the formatted table directly to the host display (only), and is therefore not captured by the $variable = … assignment and prints unconditionally - only the Read-Host response will be captured.


If you want to also output the table as data, so that it is captured in $variable, PowerShell (Core) 7+ enables a convenient Tee-Object solution, with CON (on Windows) / /dev/tty (on Unix) as the -FilePath argument (representing the console / terminal device):

# PowerShell 7+ only
[PSCustomObject]@{
  Foo = 'Bar'
  Baz = 42
} | Tee-Object -FilePath ($IsWindows ? '\\.\CON' : '/dev/tty')

Read-Host 'Enter number of campus'

Now the table both prints and is captured in $variable (along with the Read-Host response).

However, the solution relies on the data triggering implicit Format-Table formatting.
If your data would by default be presented in list format, for instance, you would need an explicit Format-Table call, which complicates matters:

  • Unless you truly want to capture the formatting instructions that Format-Table emits, you must avoid its use for outputting data - Format-* cmdlets should only be used to produce display output, not data for programmatic processing - see this answer for background information.

  • In this case you'll need a two-step approach as described for Windows PowerShell below, even in PowerShell 7+.

Unfortunately, Windows PowerShell doesn't support -FilePath CON, so you need to either collect the output in a variable first and then output and pass it to Out-Host in two separate operations, or use the Tee-Host convenience function shown in this answer, which has the added advantage of streaming its output.

Windows PowerShell / Format-Table solution (non-streaming):

# Capture the data in an aux. variable 
# and *print* it to the display.
# Note: 
#  * $table = ... by design only captures the *data*, not the Format-Table output.
#  * Enclosing the assignment in (...) passes the value *through*.
(
  $table = 
    [PSCustomObject]@{
      Foo = 'Bar'
      Baz = 42
    } 
) | Format-Table | Out-Host

# Now also *output* the data, so it can be captured.
$table

Read-Host 'Enter number of campus'
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    Thanks, @mklement0 I'm running PS version 5 (I know, but this is for work and it's a pain to get anything updated to something resembling modern), but I've used your answer to help me workout what I could do. So, I've assigned the format-table output to another variable, and then called that piped to Out-Host. – Philip Ross Apr 24 '23 at 15:03
  • 1
    Not sure I'm quite following, but perhaps I again didn't provide enough context `$table` is obtained from an API call, but it contains a lot of 'non-human friendly' details, such as GUIDs, etc, so I used `Format-Table` and selected the appropriate columns to display them in the order I wanted (number, and then name) The response to the `Read-Host` input is then fed back to the main array which contains all the generated details, which is then fed back into the script.... Am I still using things incorrectly? – Philip Ross Apr 26 '23 at 16:01
  • @PhilipRoss, now it is I who isn't quite following, but I don't think we need to resolve this. My only point - of a general nature - was: what `$data | Format-Table` outputs isn't _data_ anymore; it is _objects that provide formatting instructions_ to PowerShell, and they're only useful for that. Thus, if you want to capture _data_, for later _programmatic processing_, never capture the output from `Format-*` calls. – mklement0 Apr 26 '23 at 16:26