简体   繁体   中英

Getting a Windows command prompt contents to a text file

I want to write a batch utility to copy the output of a command prompt window to a file. I run my command prompt windows with the maximum depth of 9999 lines, and occasionally I want to grab the output of a command whose output is off-screen. I can do this manually with the keys Ctrl-A , Ctrl-C and then pasting the result into Notepad - I just want to automate it in a batch file with a call to:

SaveScreen <text file name>  

I know I can do it with redirection, but that would involve knowing that I will need to save the output of a batch command sequence beforehand.

So if I had a batch script:

call BuildPhase1.bat
if "%ErrorLevel% gtr 0 goto :ErrorExit
call BuildPhase2.bat
if "%ErrorLevel% gtr 0 goto :ErrorExit
call BuildPhase3.bat
if "%ErrorLevel% gtr 0 goto :ErrorExit

I could write:

cls
call BuildPhase1.bat
if "%ErrorLevel% gtr 0 call SaveScreen.bat BuildPhase1.err & goto :ErrorExit
call BuildPhase2.bat
if "%ErrorLevel% gtr 0 call SaveScreen.bat BuildPhase2.err & goto :ErrorExit
call BuildPhase3.bat
if "%ErrorLevel% gtr 0 call SaveScreen.bat BuildPhase3.err & goto :ErrorExit

or I could just type SaveScreen batch.log when I see that a run has failed.

My experiments have got me this far:

<!-- : Begin batch script

    @cscript //nologo "%~f0?.wsf" //job:JS
    @exit /b

----- Begin wsf script --->
<package>
  <job id="JS">
    <script language="JScript">

      var oShell = WScript.CreateObject("WScript.Shell");
      oShell.SendKeys ("hi folks{Enter}") ;

      oShell.SendKeys ("^A") ;              // Ctrl-A  (select all)
      oShell.SendKeys ("^C") ;              // Ctrl-C  (copy)
      oShell.SendKeys ("% ES") ;            // Alt-space, E, S  (select all via menu)
      oShell.SendKeys ("% EY") ;            // Alt-space, E, Y  (copy via menu)

      // ... invoke a notepad session, paste the clipboard into it, save to a file

      WScript.Quit () ; 
    </script>
  </job>
</package>

My keystrokes are making it to the command prompt so presumably I have the correct window focused - it just seems to be ignoring the Ctrl and Alt modifiers. It also recognises Ctrl-C but not Ctrl-A . Because it has ignored the Ctrl-A to select all the text, the Ctrl-C causes the batch file to think it has seen a break command.

I've seen the other answers like this one but they all deal with methods using redirection, rather than a way of doing it after the fact "on demand".

* UPDATE *

On the basis of @dxiv's pointer, here is a batch wrapper for the routine:

Get-ConsoleAsText.bat

::  save the contents of the screen console buffer to a disk file.

    @set "_Filename=%~1"
    @if "%_Filename%" equ "" @set "_Filename=Console.txt" 

    @powershell Get-ConsoleAsText.ps1 >"%_Filename%"
    @exit /b 0

The Powershell routine is pretty much as was presented in the link, except that:

  • I had to sanitise it to remove some of the more interesting character substitutions the select/copy/paste operation introduced.

  • The original saved the trailing spaces as well. Those are now trimmed.

Get-ConsoleAsText.ps1

# Get-ConsoleAsText.ps1  (based on: https://devblogs.microsoft.com/powershell/capture-console-screen/)
#  
# The script captures console screen buffer up to the current cursor position and returns it in plain text format.
#
# Returns: ASCII-encoded string.
#
# Example:
#
# $textFileName = "$env:temp\ConsoleBuffer.txt"
# .\Get-ConsoleAsText | out-file $textFileName -encoding ascii
# $null = [System.Diagnostics.Process]::Start("$textFileName")
#

if ($host.Name -ne 'ConsoleHost')                               # Check the host name and exit if the host is not the Windows PowerShell console host.
  {
  write-host -ForegroundColor Red "This script runs only in the console host. You cannot run this script in $($host.Name)."
  exit -1
  }

$textBuilder    = new-object system.text.stringbuilder          # Initialize string builder.

$bufferWidth    = $host.ui.rawui.BufferSize.Width               # Grab the console screen buffer contents using the Host console API.
$bufferHeight   = $host.ui.rawui.CursorPosition.Y
$rec            = new-object System.Management.Automation.Host.Rectangle 0,0,($bufferWidth - 1),$bufferHeight
$buffer         = $host.ui.rawui.GetBufferContents($rec)

for($i = 0; $i -lt $bufferHeight; $i++)                         # Iterate through the lines in the console buffer.
  {
  $Line = "" 
  for($j = 0; $j -lt $bufferWidth; $j++)
    {
    $cell = $buffer[$i,$j]
    $line = $line + $cell.Character
    }
  $line = $line.trimend(" ")    # remove trailing spaces.
  $null = $textBuilder.Append($line)
  $null = $textBuilder.Append("`r`n")
  }

return $textBuilder.ToString()

The contents of the console buffer can be retrieved with the PS script from PowerShell's team blog Capture console screen mentioned in a comment, now edited into OP's question.

The last line could also be changed to copy the contents to the clipboard instead of returning it.

Set-Clipboard -Value $textBuilder.ToString()

As a side note, the reasons for using a StringBuilder rather than direct concatenation are discussed in How does StringBuilder work internally in C# and How the StringBuilder class is implemented .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM