В захваченном выводе команды cmd.exe отсутствует последний перевод строки - PullRequest
0 голосов
/ 02 февраля 2019

Я пытаюсь вызвать встроенную команду cmd, например echo, в PowerShell, используя Invoke-Expression, и преобразовать ее в байтовый массив, но в выводе команды отсутствуют строки.

Пример:

([Text.Encoding]::ASCII).GetBytes((iex "cmd /c echo."))

Вместо последовательности новой строки (CRLF) ничего не возвращается.

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

tl; др:

PS> ([text.encoding]::ASCII).GetBytes(((cmd /c echo.) -join "`r`n") + "`r`n")
13
10

В качестве отступления: iex (Invoke-Expression) следует избегать .

Для получения справочной информации и предупреждений читайте далее.


Когда PowerShell захватывает вывод stdout из внешней программы , такой как cmd.exe, он возвращает массив выходных данных строк , с завершающей последовательностью новой строки , обрезанной от каждого.

В качестве отступления: Это кодировка , сообщаемая [console]::OutputEncoding, определяющая, как PowerShell интерпретирует выходные данные, которые в Windows PowerShell по умолчанию соответствуют кодовой странице OEM старой языковой системы, а на момент написания этой статьи также - все еще -в PowerShell Core в Windows , хотя , как мы надеемся, скоро изменится , учитывая, что PowerShell Core в противном случае использует (без спецификации) UTF-8 в качестве кодировки по умолчанию.

В вашем случае cmd /c echo. испустил одну последовательность новой строки Windows, CRLF, которая, с точки зрения PowerShell, составляет "`r`n" (уВы также можете использовать [Environment]::NewLine для получения строки новой строки, соответствующей платформе).

PowerShell интерпретирует это как одну пустую строку, и из-за того, что не включается завершающий символ новой строки в элементах массива, а PowerShell разворачивает одну-элемент массива, в итоге вы получите '', т. е. пустую строку - вот почему вызов ([text.encoding]::ASCII).GetBytes() не дал никакого вывода.

Вы можете собрать массив строк вывода, который PowerShell создал в одну многострочную строку вывода путем:

  • объединения элементов массива с символами новой строки (-join "`r`n")
  • с добавлением окончательного трейлингасимвол новой строки (+ "`r`n")

, как показано выше.

Предостережения : эта «повторная сборка» делает два предположения , которые могут не всегдабыть правдой:

  • То, что внешняя программа действительно генерировала последовательности Windows CRLF, а не символы UNIX LF.

    • На практике, однако, это различие редко имеет значениев PowerShell, потому что он принимает боth символ новой строки взаимозаменяемо .
  • что внешняя программа действительно испустила трейлинг символ новой строки - что обычно, но не обязательно верно.

Если эти предположения проблематичны, перенаправляет вывод в файл и , читая , что - как в ваш собственный ответ - правильное решение.

Предупреждение : > в Windows PowerShell создает файлы UTF-16LE по умолчанию (а также неизменно добавляет символ новой строки),поэтому вы не получите ASCII байтов;поэтому используйте перенаправление cmd * own для создания файла (который будет использовать устаревшую OEM-кодировку, обозначенную chcp, которая обычно является superset ASCII):

  # Note that the `>` is *inside the quoted string* to ensure that it is
  # cmd.exe that interprets it.
  # (...) around `echo.` ensures that the space before `>` doesn't become
  # part of the output.
  PS> cmd /c '(echo.) >out.txt'; [IO.File]::ReadAllBytes("$PWD\out.txt")
  13
  10
0 голосов
/ 02 февраля 2019

Я нашел решение.Не идеально, но я запишу вывод в файл, прочту его с [System.IO.File]::ReadAllBytes("path_to_the_file") и сохраню в переменную

...