Note that there are some explanatory texts on larger screens.

plurals
  1. POPowershell - redirect executable's stderr to file or variable but still have stdout go to console
    primarykey
    data
    text
    <p>I'm writing a script to download several repositories from GitHub. Here is the command to download a repo:</p> <pre><code>git clone "$RepositoryUrl" "$localRepoDirectory" </code></pre> <p>When I run this command it displays some nice progress info in the console window that I want displayed.</p> <p>The problem is that I also want to be able to detect if any errors have occurred while downloading. I found <a href="https://stackoverflow.com/questions/1215260/how-to-redirect-the-output-of-a-powershell-to-a-file-during-its-execution">this post that talks about redirecting the various streams</a>, so I tried:</p> <pre><code>(git clone "$RepositoryUrl" "$localRepoDirectory") 2&gt; $errorLogFilePath </code></pre> <p>This pipes any errors from stderr to my file, but no longer displays the nice progress info in the console.</p> <p>I can use the Tee-Object like so:</p> <pre><code>(git clone "$RepositoryUrl" "$localRepoDirectory") | Tee-Object -FilePath $errorLogFilePath </code></pre> <p>and I still get the nice progress output, but this pipes stdout to the file, not stderr; I'm only concerned with detecting errors.</p> <p>Is there a way that I can store any errors that occur in a file or (preferably) a variable, while also still having the progress info piped to the console window? I have a feeling that the answer might lie in <a href="https://stackoverflow.com/questions/12273866/is-there-a-way-to-redirect-only-stderr-to-stdout-not-combine-the-two-so-it-can">redirecting various streams into other streams as discusses in this post</a>, but I'm not really sure.</p> <p>Any suggestions are appreciated. Thanks!</p> <p>======== Update =======</p> <p>I'm not sure if the git.exe is different than your typical executable, but I've done some more testing and here is what I've found:</p> <pre><code>$output = (git clone "$RepositoryUrl" "$localRepoDirectory") </code></pre> <p>$output always contains the text "Cloning into '[localRepoDirectory]'...", whether the command completed successfully or produced an error. Also, the progress info is still written to the console when doing this. This leads me to think that the progress info is not written via stdout, but by some other stream?</p> <p>If an error occurs the error is written to the console, but in the usual white foreground color, not the typical red for errors and yellow for warnings. When this is called from within a cmdlet function and the command fails with an error, the error is NOT returned via the function's -ErrorVariable (or -WarningVariable) parameter (however if I do my own Write-Error that does get returned via -ErrorVariable). This leads me to think that git.exe doesn't write to stderr, but when we do:</p> <pre><code>(git clone "$RepositoryUrl" "$localRepoDirectory") 2&gt; $errorLogFilePath </code></pre> <p>the error message is written to the file, so that makes me think that it does write to stderr. So now I'm confused...</p> <p>======== Update 2 =======</p> <p>So with Byron's help I've tried a couple more solutions using a new process, but still can't get what I want. When using a new process I never get the nice progress written to the console.</p> <p>The 3 new methods that I've tried both use this bit of code in common:</p> <pre><code>$process = New-Object System.Diagnostics.Process $process.StartInfo.Arguments = "clone ""$RepositoryUrl"" ""$localRepoDirectory""" $process.StartInfo.UseShellExecute = $false $process.StartInfo.RedirectStandardOutput = $true $process.StartInfo.RedirectStandardError = $true $process.StartInfo.CreateNoWindow = $true $process.StartInfo.WorkingDirectory = $WORKING_DIRECTORY $process.StartInfo.FileName = "git" </code></pre> <p>Method 1 - Run in new process and read output aftewards:</p> <pre><code>$process.Start() $process.WaitForExit() Write-Host Output - $process.StandardOutput.ReadToEnd() Write-Host Errors - $process.StandardError.ReadToEnd() </code></pre> <p>Method 2 - Get output synchronously:</p> <pre><code>$process.Start() while (!$process.HasExited) { Write-Host Output - $process.StandardOutput.ReadToEnd() Write-Host Error Output - $process.StandardError.ReadToEnd() Start-Sleep -Seconds 1 } </code></pre> <p>Even though this looks like it would write the output while the process is running, it doesn't write anything until after the process exits.</p> <p>Method 3 - Get output asynchronously:</p> <pre><code>Register-ObjectEvent -InputObject $process -EventName "OutputDataReceived" -Action {Write-Host Output Data - $args[1].Data } Register-ObjectEvent -InputObject $process -EventName "ErrorDataReceived" -Action { Write-Host Error Data - $args[1].Data } $process.Start() $process.BeginOutputReadLine() $process.BeginErrorReadLine() while (!$process.HasExited) { Start-Sleep -Seconds 1 } </code></pre> <p>This does output data while the process is working which is good, but still doesn't display the nice progress info :(</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload