I am writing a script and I want to pass the values but also see them displayed
Get-Content data.txt | Tee-Object | data_processor.exe But Tee-Object always requests a file and I just want to see it on the screen.
I am writing a script and I want to pass the values but also see them displayed
Get-Content data.txt | Tee-Object | data_processor.exe But Tee-Object always requests a file and I just want to see it on the screen.
To complement zett42's helpful answer:
If you're running PowerShell (Core) 7+, you can pass the file path that represents the terminal (console) to the (positionally implied) -FilePath parameter (in Windows PowerShell, this causes an error, unfortunately - see bottom section):
# PowerShell 7+ only # Windows Get-Content data.txt | Tee-Object \\.\CON | data_processor.exe # Unix-like platforms (Linux, macOS) Get-Content data.txt | Tee-Object /dev/tty | data_processor.exe # Platform-agnostic # See coming future improvement below (-Host) Get-Content data.txt | Tee-Object ($IsWindows ? '\\.\CON': '/dev/tty') | data_processor.exe Note:
($IsWindows ? '\\.\CON': '/dev/tty') to -Host.This passes all data through while also printing it to the terminal (console), richly formatted, as usual, as it becomes available - unlike with the Tee-Object -Variable approach, which requires collecting all output in memory first (which is a concern both in terms of output timing and memory consumption).
Windows PowerShell solution: Custom proxy (wrapper) function Tee-Host wraps Out-Host while also passing its input through; use it instead of Tee-Object:
function Tee-Host { [CmdletBinding()] param( [Parameter(ValueFromPipeline)] $InputObject ) begin { $scriptCmd = { Out-Host } $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin) $steppablePipeline.Begin($PSCmdlet) } process { # Pass to Out-Host, and therefore to the host (terminal) $steppablePipeline.Process($InputObject) # Pass through (to the success stream) $InputObject } end { $steppablePipeline.End() } } In effect, Tee-Host behaves like Tee-Object \\.\CON / Tee-Object /dev/tty in PowerShell 7+, where Tee-Host works too.
Even in PowerShell 7+ Tee-Host may be preferable, because it uses colored output unconditionally, whereas the coloring behavior of Tee-Object \\.\CON / Tee-Object /dev/tty depends on the value of $PSStyle.OutputRendering
It is the use of a proxy function with a steppable pipeline wrapping Out-Host that ensures that the to-host formatted output looks the same as when the input is directly sent to the host.
You can output to a variable instead of a file:
Get-Content data.txt | Tee-Object -Variable data | data_processor.exe $data # Output This passes content to "data_processor.exe" and stores it in variable $data. Data will be shown only when the .exe has finished.
Use ForEach-Object to examine output of Get-Content before each line is being send to the .exe:
Get-Content data.txt | ForEach-Object { Write-Host $_ # Output line to console $_ # Forward line to next command in chain } | data_processor.exe This pattern could be made more succinct and reusable, by writing a small filter function:
Filter Write-HostAndForward { Write-Host $_ # Output line to console $_ # Forward line to next command in chain } Now we can write:
Get-Content data.txt | Write-HostAndForward | data_processor.exe Remarks:
While Write-HostAndForward works for simple input, like strings received from Get-Content, for complex objects it typically doesn't produce the same output as we normally see in the console. That is because Write-Host simply converts the input to string using the .ToString() method, which skips PowerShells rich formatting system.
You might be tempted to simply replace Write-Host by Out-Host, but as mklement0 explains, it would format the input objects individually, which will produce a header for each object for table-formatted output. To avoid that, mklement0's answer shows different ways to produce the expected formatted output.
Tee-Objectdoes, though I can see why you'd think it should. You probably have to replace it withForEach-Object{Write-Host $_; $_}instead and run everything through a loop.data_processor.exeneeds all the lines of input (only four actually) at once, each line isn't independent.-rawswitch onGet-Content. That will read the entire file, then it can be passed to theForEach-Objectloop where all four lines will be written to the host and passed at once todata_processor.exe. Or wrap everything before| data_processor.exein parenthesis.