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.
CodePudding user response:
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.
CodePudding user response:
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
This passes all data through while also printing it to the terminal (console), richly formatted, as usual.
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 likeTee-Object CON
/Tee-Object /dev/tty
in PowerShell 7 , whereTee-Host
works too.Even in PowerShell 7
Tee-Host
may be preferable, because it uses colored output unconditionally, whereas the coloring behavior ofTee-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.