3

I want to pipe the output of a command to a file:

PS C:\Temp> create-png > binary.png

I noticed that Powershell changes the encoding and that I can manually give an encoding:

PS C:\Temp> create-png | Out-File "binary.png" -Encoding OEM

However there is no RAW encoding option, even the OEM option changes newline bytes (0xA resp 0xD) to the windows newline byte sequence (0xD 0xA) thereby ruining any binary format.

How can I prevent Powershell from changing the encoding when piping to a file?

Related questions

Community
  • 1
  • 1
Micha Wiedenmann
  • 17,330
  • 20
  • 79
  • 123

3 Answers3

4

Try using set-content:

create-png | set-content -path myfile.png -encoding byte

If you need additional info on set-content just run

get-help set-content

You can also use 'sc' as a shortcut for set-content.

Tested with the following, produces a readable PNG:

function create-png()
{
    [System.Drawing.Bitmap] $bitmap = new-object 'System.Drawing.Bitmap'([Int32]32,[Int32]32);
    $graphics = [System.Drawing.Graphics]::FromImage($bitmap);
    $graphics.DrawString("TEST",[System.Drawing.SystemFonts]::DefaultFont,[System.Drawing.SystemBrushes]::ActiveCaption,0,0);
    $converter = new-object 'System.Drawing.ImageConverter';
    return([byte[]]($converter.ConvertTo($bitmap, [byte[]])));
}

create-png | set-content -Path 'fromsc.png' -Encoding Byte

If you are calling out to a non-PowerShell executable like ipconfig and you just want to capture the bytes from Standard Output, try Start-Process:

Start-Process -NoNewWindow -FilePath 'ipconfig' -RedirectStandardOutput 'output.dat'
RickH
  • 2,266
  • 13
  • 17
  • Added an example and a missing argument for set-content to keep the byte encoding. If your create-png is passing something to the pipeline other than a byte array than this may not work, so it would be helpful if you included some information about what create-png is actually outputting. – RickH Jan 27 '15 at 13:42
  • `create-png` is an arbitrary command (not commandlet) (for example: ipconfig). I assume that the output of commands is a string. I tried with `-encoding byte` and it failed with: content must be byte (as you predicted). I also noted that after I ran your command (which failed) ipconfig didn't print any output anymore. – Micha Wiedenmann Jan 27 '15 at 14:03
  • If you let the PowerShell pipeline interact with the stream, it's going to split it into an array of strings and then the output formatter is going to use Windows newlines as you have seen. If you don't want PowerShell to alter the stream, you can grab it directly using .Net classes like shown in: http://stackoverflow.com/questions/1390559/how-to-get-the-output-of-a-system-diagnostics-process – RickH Jan 27 '15 at 16:37
  • If you update your answer to work for normal commands (for example ipconfig, which gives presumably string output(?)) I will accept it. Currently it is interesting and relevant information but not suitable as an answer, imho. – Micha Wiedenmann Jan 30 '15 at 12:35
  • When you run a command like ipconfig, it's not outputting a type, it's actually writing bytes to stdout which is a stream. So you can't really think of it as returning a string, it's more like characters, encoded as bytes, output to a stream. I'll update the answer above for the scenario where you just want to capture the bytes. – RickH Jan 30 '15 at 21:44
2

Create a batchfile containing the line

create-png > binary.png

and call that from Powershell via

& cmd /c batchfile.bat

If you'd rather pass the command to cmd as command line parameter:

$x = "create-png > binary.png"
& cmd /c $x
Hardy
  • 51
  • 2
1

According to this well written blog article

When using curl with PowerShell, never, never redirect to file with >. Always use the –o or –out switch. If you need to stream the output of curl to another utility (say gpg) then you need to sub-shell into cmd for the binary streaming or use temporary files.

Micha Wiedenmann
  • 17,330
  • 20
  • 79
  • 123