Получение содержимого командной строки Windows в текстовый файл

Я хочу написать пакетную утилиту для копирования вывода окна командной строки в файл. Я запускаю окна командной строки с максимальной глубиной 9999 строк, и иногда мне нужно получить вывод команды, вывод которой находится за пределами экрана. Я могу сделать это вручную с помощью клавиш Ctrl-A, Ctrl-C, а затем вставить результат в блокнот — я просто хочу автоматизировать это в пакетном файле с вызовом:

SaveScreen <text file name>  

Я знаю, что могу сделать это с перенаправлением, но для этого нужно знать, что мне нужно заранее сохранить вывод последовательности пакетных команд.

Итак, если бы у меня был пакетный скрипт:

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

Я мог бы написать:

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

или я могу просто набрать SaveScreen batch.log, когда увижу, что запуск не удался.

Мои эксперименты завели меня так далеко:

<!-- : 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>

Мои нажатия клавиш попадают в командную строку, поэтому, по-видимому, я сфокусировал правильное окно - кажется, что оно просто игнорирует модификаторы Ctrl и Alt. Он также распознает Ctrl-C, но не Ctrl-A. Поскольку он проигнорировал Ctrl-A для выбора всего текста, Ctrl-C заставляет пакетный файл думать, что он видел команду разрыва.

Я видел другие ответы, такие как этот, но все они имеют дело с методами, использующими перенаправление, а не способ сделать это постфактум «по требованию».

* ОБНОВЛЕНИЕ *

На основе указателя @dxiv вот пакетная оболочка для подпрограммы:

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

Процедура Powershell почти такая же, как была представлена ​​​​в ссылке, за исключением того, что:

  • Мне пришлось очистить его, чтобы удалить некоторые из наиболее интересных замен символов, введенных операцией выбора/копирования/вставки.

  • Оригинал также сохранил конечные пробелы. Те сейчас обрезаны.

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()

person rossmcm    schedule 02.05.2020    source источник
comment
Может быть, что-то вроде Захват экрана консоли (с помощью powershell).   -  person dxiv    schedule 03.05.2020
comment
Похоже, что он может получить доступ не более чем к видимой области экрана. Кажется, что он берет прямоугольную область экрана, а затем возвращает текст в этой области. Это кажется странным способом сделать это.   -  person rossmcm    schedule 03.05.2020
comment
PSHostRawUserInterface.GetBufferContents получает весь буфер независимо от того, что видно в окне консоли. И это работает на консоли хоста, которая может быть командной строкой, не обязательно собственной консолью PowerShell.   -  person dxiv    schedule 03.05.2020
comment
Заметки Если прямоугольник находится полностью за пределами экранного буфера, будет возвращен массив BufferCell, состоящий из нулевых строк и столбцов. Если прямоугольник частично находится за пределами экранного буфера, будет считана и возвращена область, в которой перекрываются экранный буфер и прямоугольник. Размер возвращаемого массива такой же, как у r. Каждая BufferCell в неперекрывающейся области этого массива устанавливается следующим образом:   -  person rossmcm    schedule 03.05.2020
comment
(отрывок из ссылки) доступен ли полный текст в другом месте?   -  person rossmcm    schedule 03.05.2020
comment
Верно, но акцент в этом замечании сделан на buffer. Возможно, это неудачный выбор слов, но он относится к буферу консоли, а не к окну. Вы можете использовать код в ссылке, которую я разместил, чтобы убедиться, что он действительно захватывает весь буфер.   -  person dxiv    schedule 03.05.2020
comment
Хорошо спасибо. Все хорошо. Переупакуйте свой комментарий как ответ, и я поставлю ему зеленую галочку. Я немного подчистил связанный код и добавлю его к вопросу.   -  person rossmcm    schedule 03.05.2020
comment
Рад, что это помогло, и я тоже узнал что-то новое сегодня;-)   -  person dxiv    schedule 03.05.2020
comment
чтобы Ctrl-A, Ctrl-V и Ctrl-C работали, необходимо изменить свойства (или значения по умолчанию для постоянного изменения). Вкладка «Параметры», отметьте Enable Ctrl key Shortcuts в параметрах редактирования.   -  person Stephan    schedule 03.05.2020


Ответы (1)


Содержимое буфера консоли можно получить с помощью сценария PS из блога команды PowerShell Capture console. экран, упомянутый в комментарии, теперь отредактирован в вопросе OP.

Последняя строка также может быть изменена, чтобы копировать содержимое в буфер обмена, а не возвращать его.

Set-Clipboard -Value $textBuilder.ToString()

В качестве примечания: причины использования StringBuilder вместо прямой конкатенации обсуждаются в разделах Как StringBuilder работает внутри C# и Как реализован класс StringBuilder.

person dxiv    schedule 03.05.2020