Powershell: out-default and switch "-transcript"

Created on 15 Oct 2018  路  5Comments  路  Source: PowerShell/PowerShell

hello

if i add out-default in middle of this expression it return enexpected result but if i add switch "-transcript" it return the exact result why ? i dont understand the use of this switch

Steps to reproduce


PS C:\> Get-Process -Id $PID

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     57    27.50      62.77       6.11     368   6 pwsh


PS C:\> Get-Process -Id $PID | Select-Object name,id

Name  Id
----  --
pwsh 368


PS C:\> Get-Process -Id $PID | out-default | Select-Object name,id

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     58    27.82      63.92       6.64     368   6 pwsh


PS C:\> Get-Process -Id $PID | out-default -Transcript | Select-Object name,id
Name  Id
----  --
pwsh 368

Environment data

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.1.0
PSEdition                      Core
GitCommitId                    6.1.0
OS                             Microsoft Windows 6.3.9600
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

thanks

Area-Cmdlets-Core Issue-Bug

Most helpful comment

@iSazonov given the intended behaviour of Out-Default (output to console, not pipeline) I would be more inclined to think that the fact that adding the -Transcript switch changing that completely is most likely a bug -- unless you or one of the microsoft folks here can speak to what the -Transcript switch is supposed to do (given that it's undocumented).

All 5 comments

Inserting just Out-Default sends all pipeline input directly to the console, ignoring the remaining pipeline segments - which is expected behavior.

-Transcript is currently undocumented, but, from what I gather, its purpose is to send output _just_ to a transcript (previously started with Start-Transcript), and not also to the host (console/terminal).

The surprising aspect is that it still _passes the objects through_, unlike without -Transcript, but whether the final pipeline segment still produces host output seemingly depends on whether a _cmdlet_ (yes) or a _script block_ (no) tries to produce output.

For instance, the following does _not_ produce output, due to using a script block in the final segment:

# No output.
Get-Process -Id $PID | out-default -Transcript | ForEach-Object { $_.Name }

Note that the script block still _receives_ the input object, but it cannot produce output, neither implicitly nor with Write-Output - you can, however, write to a _different_ stream; e.g.:

# DOES write to the verbose stream.
Get-Process -Id $PID | out-default -Transcript | ForEach-Object { Write-Verbose -vb $_.Name  }

My sense is that both behaviors are ultimately the manifestation of a _bug_, because, arguably, Out-Default -Transcript should behave like Out-Default alone and _not_ pass anything on through the pipeline.

thanks for your comments

here another cases:

PS C:\> # why run fast and no output ?
PS C:\> 1..1gb | Out-Default -Transcript | select -First 5
ps C:\> no scriptblock but no output
PS C:\> Get-Process -Id $PID | Out-Default -Transcript | ForEach-Object -MemberName name

-transcript emit output to pipeline if it use with transcription but still remain mysterious cases




rm  "$env:temp\transcript.log" -ea 0
$null = Start-Transcript -Path "$env:temp\transcript.log"
1 | Out-Default
2
$null = Stop-Transcript
 # in console
2
gc "$env:temp\transcript.log"
# in file
1
2
rm  "$env:temp\transcript.log" -ea 0
$null = Start-Transcript -Path "$env:temp\transcript.log"
1 | Out-Default -Transcript
2
$null = Stop-Transcript
 # in console
2
gc "$env:temp\transcript.log"
# in file
1
1
2
rm  "$env:temp\transcript.log" -ea 0
$null = Start-Transcript -Path "$env:temp\transcript.log"
1..10 | Out-Default -transcript | select -First 5
2
$null = Stop-Transcript

# in console
2
gc "$env:temp\transcript.log"
# in file
1
1
2
2
3
3
4
4
5
2
rm  "$env:temp\transcript.log" -ea 0
$null = Start-Transcript -Path "$env:temp\transcript.log"
Get-Process -Id $PID | out-default -Transcript | ForEach-Object { $_.Name }
2
$null = Stop-Transcript

# in console
2

gc "$env:temp\transcript.log"
# in file
pwsh

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     58    28.04      63.11       6.02    2280   1 pwsh


2

i dont see the importance of this switch

@iSazonov given the intended behaviour of Out-Default (output to console, not pipeline) I would be more inclined to think that the fact that adding the -Transcript switch changing that completely is most likely a bug -- unless you or one of the microsoft folks here can speak to what the -Transcript switch is supposed to do (given that it's undocumented).

I peeked at the source code and found this:

https://github.com/PowerShell/PowerShell/blob/e5a41777365d8edc9e2bf5457c2bd6f2a69e5db9/src/System.Management.Automation/FormatAndOutput/out-console/OutConsole.cs#L45-L52

While I don't have the full picture, I infer the following:

  • The switch is used _internally_ , in the context of using the PowerShell SDK (API), and may never have been meant to be used from PowerShell code.

  • Passing the objects through is intentional.


Sticking an Out-Default in the _middle_ of a pipeline - with or without -Transcript - doesn't make much sense in general, given that Out-* cmdlets are usual the _final_ pipeline stage.

Given that, I wonder if the inconsistency we've observed - with -Transcript present, (at least some) cmdlets still producing output while script blocks aren't - is worth fixing at all.

However, there _is_ a _potentially_ useful application for Out-Default -Transcript (as the last pipeline segment) which I've alluded to before, and it's something that @PetSerAl had pointed out to me:

With a transcript ongoing, you can selectively suppress _console_ output for a given command while still sending the output to the _transcript_.

Given the comments in the source code, this is likely an unintentional feature, however, and, in fact, it is currently _buggy_:

Start-Transcript t.txt
'foo'   # outputs to console *and* to the transcript
'bar' | Out-Default -Transcript  # outputs to the transcript *only*
Stop-Transcript

In the console, you'll see:

Transcript started, output file is t.txt
foo  # Note how only 'foo' was printed to the console, not 'bar'
Transcript stopped, output file is /path/to/t.txt

In the transcript you'll see:

**********************
PowerShell transcript start
Start time: 20181016235404
# ....
**********************
Transcript started, output file is t.txt
foo
bar
bar  # !! bug - 'bar' was written *twice*
**********************
PowerShell transcript end
End time: 20181016235404
**********************

It's conceivable that users who have discovered the to-transcript-only behavior are relying on it (the bug notwithstanding), so it's probably worth fixing the bug (and, who knows, perhaps that will implicitly also fix the inconsistent middle-of-the-pipeline behavior).

given that Out-* cmdlets are usual the final pipeline stage.

In middle of pipeline I believe we should use Out-String.

Was this page helpful?
0 / 5 - 0 ratings