3

I'm writing a script that will perform some git actions and I want to use Start-Transcript to monitor it. The transcript is however missing most of the git output.

I've tried to pipe the git output to both Out-Host and Out-Default but neither work.

Here's my code...

$DateTime = Get-Date -Format "yyyyMMdd_HHmmss"
$TranscriptName = "PSTranscript_$DateTime"

Start-Transcript -Path ".\$TranscriptName.txt"

git --bare clone <GIT_REPO_URL> repo | Out-Default

Stop-Transcript

Here's my console output...

Transcript started, output file is .\PSTranscript_20191119_155424.txt
Cloning into 'repo'...
remote: Counting objects: 58975, done.
remote: Compressing objects: 100% (21457/21457), done.
remote: Total 58975 (delta 43348), reused 51727 (delta 37145)
Receiving objects: 100% (58975/58975), 70.46 MiB | 3.95 MiB/s, done.
Resolving deltas: 100% (43348/43348), done.
Checking out files: 100% (3878/3878), done.
Transcript stopped, output file is .\PSTranscript_20191119_155424.txt

And here's what is captured in the transcript, note that some of the git output is missing

**********************
Windows PowerShell transcript start
Start time: 20191119155424
Username: 
RunAs User: 
Configuration Name: 
Machine: 
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 20644
PSVersion: 5.1.17134.858
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.17134.858
BuildVersion: 10.0.17134.858
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
Transcript started, output file is .\PSTranscript_20191119_155424.txt
**********************
Windows PowerShell transcript end
End time: 20191119155457
**********************
Zam
  • 1,121
  • 10
  • 27
  • 2
    https://stackoverflow.com/a/47367768/6309 might help. – VonC Nov 19 '19 at 21:10
  • 1
    `Start-Transcript` should capture everything regardless of the output stream. However, it seems that piping `git` command output to `Out-Default` causes output to not be logged in the transcript.] – codewario Nov 19 '19 at 21:47
  • 1
    I've amended my answer to reflect the conclusion that `Out-Default` should _never_ be called directly from user code, based on [this discussion on GitHub](https://github.com/PowerShell/PowerShell/issues/11135#issuecomment-556461374). – mklement0 Nov 22 '19 at 12:39

3 Answers3

4

Edit: I make a mistake in leaving the Out-Default in my original code. This hits a bug in Out-Default that specifically affects stderr. Removing the Out-Default resulted in fixing my script and it now successfully transcribes git output.


@VonC posted a very helpful link that pointed me in the right direction!

All that needed done was adding the GIT_REDIRECT_STDERR environment variable with the value 2>&1 to Windows User environment variables.

If you're on Windows, here's a nifty PowerShell command you can run to add the environment variable.

[System.Environment]::SetEnvironmentVariable("GIT_REDIRECT_STDERR", "2>&1", "User")

Below is what my new transcript looks like...

**********************
Windows PowerShell transcript start
Start time: 20191119165056
Username: 
RunAs User: 
Configuration Name: 
Machine: 
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 16440
PSVersion: 5.1.17134.858
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.17134.858
BuildVersion: 10.0.17134.858
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
Transcript started, output file is .\PSTranscript_20191119_165056.txt
Cloning into bare repository 'repo'...
remote: Counting objects: 58975, done.
remote: Compressing objects: 100% (21457/21457), done.
remote: Total 58975 (delta 43347), reused 51727 (delta 37145)
Receiving objects: 100% (58975/58975), 70.33 MiB | 6.04 MiB/s, done.
Resolving deltas: 100% (43347/43347), done.
**********************
Windows PowerShell transcript end
End time: 20191119165115
**********************
mklement0
  • 382,024
  • 64
  • 607
  • 775
Zam
  • 1,121
  • 10
  • 27
  • 1
    Thanks! For my environment, I had to use this line, which should be functionalty equivalent: $env:GIT_REDIRECT_STDERR = "2>&1" – beeks Mar 11 '21 at 17:52
4

There's no reason to call Out-Default - just use your git command as-is, and your problem will go away: both its stdout and stderr streams will be transcribed.

git writes status information to stderr by default, and the - mistaken - use of Out-Default affects stderr output specifically, as described in the bottom section.

The following example demonstrates that both stdout and stderr output from external programs are captured in the transcript:

$file = [IO.Path]::GetTempFileName()

"--- DIRECT OUTPUT ---`n"

Start-Transcript $file

# Execute a command that produces
# both stdout and stderr output.
# Do NOT use Out-Default.
if ($env:OS -eq 'Windows_NT') {  # Windows
  cmd /c 'echo hi & nosuch'
} else {                         # macOS, Linux
  sh -c 'echo hi; nosuch'
}

Stop-Transcript

"`n--- CORE CONTENT OF TRANSCRIPT ---"

# Print the core of the transcript.
((Get-Content -Raw $file) -split '(?m)^\*+\s*$')[2]

Remove-Item $file

On Windows, you'll see something like the following, demonstrating that both streams were captured:

--- DIRECT OUTPUT ---

Transcript started, output file is C:\Users\jdoe\AppData\Local\Temp\tmp342C.tmp
hi
'nosuch' is not recognized as an internal or external command,
operable program or batch file.
Transcript stopped, output file is C:\Users\jdoe\AppData\Local\Temp\tmp342C.tmp

--- CORE CONTENT OF TRANSCRIPT ---

Transcript started, output file is C:\Users\jdoe\AppData\Local\Temp\tmp342C.tmp
hi
'nosuch' is not recognized as an internal or external command,
operable program or batch file.

The purpose of the Out-Default cmdlet:

Out-Default is not meant to be called from user code.

Instead, it is meant to be used only by PowerShell host applications, including by PowerShell itself. It creates pretty-printed string representations of the output objects using PowerShell's output-formatting system and sends them to the host for display.

The reason that it is a public cmdlet is that you are allowed to override it in order to define a custom output formatter, although doing so is rare.

Overriding is as simple as defining an advanced Out-Default function in your session, which must have the same parameter declarations and pipeline-binding behavior. You can scaffold such a function via a wrapper (proxy) function, as demonstrated in the bottom section of this answer). Note that in order to produce visible output from your function, you must send your custom-formatted strings either to the original Out-Default or use the host APIs to print them (Write-Host, in the simplest case).


Bug:

Your use of Out-Default - though ill-advised - should arguably still have worked.

While that is a moot point for Out-Default, given that it shouldn't be called directly, Out-Host exhibits the same problem (as of PowerShell Core 7.0.0-preview.6), and there are legitimate reasons to call Out-Host, namely to explicitly print to the display only (and doing so should not affect transcription behavior).

Specifically, if you use Out-Host explicitly, stderr output from external programs is unexpectedly not recorded in the transcript. (By contrast, the problem doesn't surface with PowerShell commands.)

The problem has been reported in GitHub issue #11134.

mklement0
  • 382,024
  • 64
  • 607
  • 775
2

Start-Transcript should capture everything written to the console host regardless of which stream it writes to. However, I did notice that when I pipe a git command to Out-Default, I get NOTHING written to the transcript for that command, even though it displays to the console.

I can't explain why this happens, but remove | Out-Default from your clone command and it should log the output to the transcript.

codewario
  • 19,553
  • 20
  • 90
  • 159
  • 1
    Thanks for the sanity check, I was reading and expecting Out-Default to do the trick but experienced the same thing. It does however seem that redirecting the output is doing the trick. – Zam Nov 19 '19 at 21:58
  • This is going to drive me absolutely nuts. I don't have that set on my workstation and I still get `git` output logged to the transcript unless I pipe it to `Out-Default`. I thought maybe it might be a quirk of using ConEmu as my console host but even using plain `powershell.exe` I get the same behavior. – codewario Nov 19 '19 at 22:06
  • 2
    Good points. Note that it's _stderr_ output from external programs, specifically, that isn't getting recorded, but the main point is indeed that there's no reason to use `Out-Default` to begin with. – mklement0 Nov 20 '19 at 15:51
  • I've amended my answer to reflect the conclusion that `Out-Default` should _never_ be called directly from user code, based on [this discussion on GitHub](https://github.com/PowerShell/PowerShell/issues/11135#issuecomment-556461374). While the `Out-Default` behavior is therefore a moot point, the same problem (omitted stderr output from the transcript) affects `Out-Host` too, and `Out-Host` _does_ have legitimate uses. – mklement0 Nov 22 '19 at 12:39