【问题标题】:How to get original binary data from external command output in PowerShell?如何从 PowerShell 中的外部命令输出中获取原始二进制数据?
【发布时间】:2018-04-07 09:56:05
【问题描述】:

我在这里读到,当您在 powershell 中运行外部命令时,它们的输出总是被解释为字符串或字符串数​​组:https://stackoverflow.com/a/35980675/983442

我正在尝试处理来自外部命令的二进制输出,但似乎 PowerShell 只能给我字符串。

这让我想知道,使用什么编码将二进制数据转换为字符串?而且,它如何解释换行符以将二进制数据划分为字符串数组?它似乎仅在 \n 字符上分裂,但我确信它也会在 \r\n 上分裂。

是否有可靠的方法来获取 powershell 给我的字符串并将它们转换回字节数组?

例如,假设我有一个包含以下内容的批处理文件,将其命名为thing.bat

@echo off
type image.jpg

然后我运行以下 powershell:

PS> $x = & .\thing.bat
PS> $x.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array


PS> $x[0].gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object


PS> $x.count
36

拥有$x 变量后,如何在PowerShell 中可靠地重新创建此image.jpg?

【问题讨论】:

  • 想解释否决票?
  • 我可以想象反对者想看一些示例代码。此外,这似乎是每个用户都应该通过尝试自己回答的问题。但是我认为这是一个有用的问题,但也希望看到一些示例命令及其输出。
  • 你最好加个例子,我们可以测试一下……
  • @Clijsters 我已经编辑了我的问题。
  • 一件事是使用Out-File(您可以在其中设置-Encdoding 和通过例如Get-Content -Encoding OEM读回它

标签: shell powershell encoding pipeline


【解决方案1】:

PowerShell 假定您调用的每个外部程序仅在其输出流上提供strings。 虽然这与现实相差不远,但人们可能希望从外部程序中获取真实字节。 为此,我们将“从头开始”创建一个新流程

$procInfo = New-Object System.Diagnostics.ProcessStartInfo -Property @{
    FileName = "cmd.exe"
    Arguments = "thing.bat"
    RedirectStandardError = $true
    RedirectStandardOutput = $true
    UseShellExecute = $false
}
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo = $procInfo
$proc.Start() | Out-Null
$proc.WaitForExit()

当各自的 Redirect 属性设置为 $true 时,它为 StandardOutputStandardError 提供了一个 StreamReader

现在要获取流的内容,我们可以轻松地使用 ReadToEnd() 就像 $outContent = $proc.StandardOutput.ReadToEnd() 一样,但这只会再次给我们一个字符串。

StreamReader 为我们提供了以下方法(以及其他方法):

Read             Method   int Read(), int Read(char[] buffer, int index, int count)
ReadAsync        Method   System.Threading.Tasks.Task[int] ReadAsync(char[] buffer, int index, int count)
ReadBlock        Method   int ReadBlock(char[] buffer, int index, int count)
ReadBlockAsync   Method   System.Threading.Tasks.Task[int] ReadBlockAsync(char[] buffer, int index, int count)
ReadLine         Method   string ReadLine()
ReadLineAsync    Method   System.Threading.Tasks.Task[string] ReadLineAsync()
ReadToEnd        Method   string ReadToEnd()
ReadToEndAsync   Method   System.Threading.Tasks.Task[string] ReadToEndAsync()

只需创建一个 char[] 缓冲区并将其传递给 Read() 并按照您的意愿使用它:

$length = $proc.StandardOutput.Length
$s = New-Object 'char[]' $length
$proc.StandardOutput.Read($s, 0, $length - 1)

第二个 - 更简单但不太灵活的解决方案:

如果您将文件写入磁盘没有问题,您可以轻松地将程序的标准输出重定向到带有-Encoding Oem 的文件,然后使用Get-Content 再次读取它:

& .\thing.bat | Out-File -FilePath "C:/tmp/out.txt" -Encoding Oem
$rawContent = Get-Content -Path "C:/tmp/out.txt" -Encoding Oem

【讨论】:

  • 我想这确实回答了我的问题,但它实际上并没有帮助我。我有一个第三方程序调用我的 powershell 脚本并将二进制数据传递给它。该图像只是用于测试的占位符。
  • 如果第 3 方程序调用您的脚本而不是相反,则图像不是一个好的占位符。你能告诉我们这个程序调用的确切命令行吗?
  • 我可以控制这个程序调用的命令行——所以我将它传递给“powershell.exe -file script.ps1”,然后它通过标准输入传递一个图像。第三方程序是openssh。我正在尝试在 windows 上的 authorized_keys 文件中使用命令 (ForceCommand) 选项。
  • 我应该只编写自己的可执行文件来将标准输入保存到磁盘。
  • 我想我最终会使用这些 cmdlet 来完成我所需要的:powershellgallery.com/packages/Use-RawPipeline/1.2
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
  • 2014-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-22
  • 2011-05-24
相关资源
最近更新 更多