Powershell - redirect executable's stderr to file or variable but still have stdout go to console -


i'm writing script download several repositories github. here command download repo:

git clone "$repositoryurl" "$localrepodirectory" 

when run command displays nice progress info in console window want displayed.

the problem want able detect if errors have occurred while downloading. found this post talks redirecting various streams, tried:

(git clone "$repositoryurl" "$localrepodirectory") 2> $errorlogfilepath 

this pipes errors stderr file, no longer displays nice progress info in console.

i can use tee-object so:

(git clone "$repositoryurl" "$localrepodirectory") | tee-object -filepath $errorlogfilepath 

and still nice progress output, pipes stdout file, not stderr; i'm concerned detecting errors.

is there way can store errors occur in file or (preferably) variable, while still having progress info piped console window? have feeling answer might lie in redirecting various streams other streams discusses in post, i'm not sure.

any suggestions appreciated. thanks!

======== update =======

i'm not sure if git.exe different typical executable, i've done more testing , here i've found:

$output = (git clone "$repositoryurl" "$localrepodirectory") 

$output contains text "cloning '[localrepodirectory]'...", whether command completed or produced error. also, progress info still written console when doing this. leads me think progress info not written via stdout, other stream?

if error occurs error written console, in usual white foreground color, not typical red errors , yellow warnings. when called within cmdlet function , command fails error, error not returned via function's -errorvariable (or -warningvariable) parameter (however if own write-error returned via -errorvariable). leads me think git.exe doesn't write stderr, when do:

(git clone "$repositoryurl" "$localrepodirectory") 2> $errorlogfilepath 

the error message written file, makes me think write stderr. i'm confused...

======== update 2 =======

so byron's i've tried couple more solutions using new process, still can't want. when using new process never nice progress written console.

the 3 new methods i've tried both use bit of code in common:

$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" 

method 1 - run in new process , read output aftewards:

$process.start() $process.waitforexit() write-host output - $process.standardoutput.readtoend()     write-host errors - $process.standarderror.readtoend() 

method 2 - output synchronously:

$process.start() while (!$process.hasexited) {     write-host output - $process.standardoutput.readtoend()     write-host error output - $process.standarderror.readtoend()      start-sleep -seconds 1 } 

even though looks write output while process running, doesn't write until after process exits.

method 3 - output asynchronously:

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 } 

this output data while process working good, still doesn't display nice progress info :(

i think have answer. i'm working powershell while , created several build systems. sorry if script bit long, works.

$dir = <your dir> $global:log = <your log file must in global scope> # not global = won't work  function create-process {     $process = new-object -typename system.diagnostics.process     $process.startinfo.createnowindow = $false     $process.startinfo.redirectstandarderror = $true     $process.startinfo.useshellexecute = $false     return $process }  function terminate-process {     param([system.diagnostics.process]$process)      $code = $process.exitcode     $process.close()     $process.dispose()     remove-variable process     return $code }  function launch-process {     param([system.diagnostics.process]$process, [string]$log, [int]$timeout = 0)      $errorjob = register-objectevent -inputobject $process -eventname errordatareceived -sourceidentifier common.launchprocess.error -action {         if(-not [string]::isnullorempty($eventargs.data)) {             "error - $($eventargs.data)" | out-file $log -encoding ascii -append             write-host "error - $($eventargs.data)"         }     }     $outputjob = register-objectevent -inputobject $process -eventname outputdatareceived -sourceidentifier common.launchprocess.output -action {         if(-not [string]::isnullorempty($eventargs.data)) {             "out - $($eventargs.data)" | out-file $log -encoding ascii -append             write-host "out - $($eventargs.data)"         }     }      if($errorjob -eq $null) {         "error - error job null" | out-file $log -encoding ascii -append         write-host "error - error job null"     }      if($outputjob -eq $null) {         "error - output job null" | out-file $log -encoding ascii -append         write-host "error - output job null"     }      $process.start()      $process.beginerrorreadline()      if($process.startinfo.redirectstandardoutput) {         $process.beginoutputreadline()      }      $ret = $null     if($timeout -eq 0)     {         $process.waitforexit()         $ret = $true     }     else     {         if(-not($process.waitforexit($timeout)))         {             write-host "error - process not completed, after specified timeout: $($timeout)"             $ret = $false         }         else         {             $ret = $true         }     }      # cancel event registrations     remove-event * -erroraction silentlycontinue     unregister-event -sourceidentifier common.launchprocess.error     unregister-event -sourceidentifier common.launchprocess.output     stop-job $errorjob.id     remove-job $errorjob.id     stop-job $outputjob.id     remove-job $outputjob.id      $ret }  $repo = <your repo>  $process = create-process $process.startinfo.redirectstandardoutput = $true $process.startinfo.filename = "git.exe" $process.startinfo.arguments = "clone $($repo)" $process.startinfo.workingdirectory = $dir launch-process $process $global:log terminate-process $process 

the log file must in global scope because routine runs event processing not in script scope.

sample of log file:

out - cloning ''... error - checking out files: 22% (666/2971)
error - checking out files: 23% (684/2971)
error - checking out files: 24% (714/2971)


Comments

Popular posts from this blog

linux - xterm copying to CLIPBOARD using copy-selection causes automatic updating of CLIPBOARD upon mouse selection -

qt - Errors in generated MOC files for QT5 from cmake -