4

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

4 Answers 4

5

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' 
Sign up to request clarification or add additional context in comments.

5 Comments

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.
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.
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: stackoverflow.com/questions/1390559/…
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.
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.
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 

Comments

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.

Comments

1


Powershell regard output as string.But windows-1252 maps every byte to character,you can try use this encoding.
It's a trick though it is not efficient.
In my case,powershell version is 5.1,Out-File or > operator doesn't support windows 1252,so I have to use WriteAllText method. example:

[console]::outputencoding=[console]::inputencoding=[System.Text.Encoding]::GetEncoding(1252) $result=python zipbomb --mode=quoted_overlap --num-files=250 --compressed-size=21179 [IO.File]::WriteAllText("$pwd\result.zip",$result,[System.Text.Encoding]::GetEncoding(1252)) 

or simply by Start-Process with -RedirectStandardOutput option

Start-Process -FilePath "python.exe" -ArgumentList "zipbomb --mode=quoted_overlap --num-files=250 --compressed-size=21179" -RedirectStandardOutput output.zip 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.