I've been working a lot with powershell recently. I must admit that after a steep learning curve, it is a great language.
Pipelining objects (instead of plain text) is a beautiful idea. If you compare scripts written in powershell and bash, the powershell ones are much shorter and easier to read.
Basically you can perform advanced scripting without using the magic formulas of sed, awk and their friends.
If you've never played with powershell and use windows on a daily basis, just start...you will enjoy it. But please, give it some time, do not expect to master it in a few days.
I've been implementing scripts to automatically extract git commits and faced a major problem. git commands usually output directly on stdout and do not provide command line options to output in a file (e.g git show). Everything is more or less OK as long as the output is text, if you want to deal with binary output, you start entering hell...
First of all, you have to understand powershell string are UTF-16 !!!. So if you do something like this:
git show master:image.png | out-file 'image-master.png'powershell will interpret git output as text lines. Therefore, it will look for carriage return characters to split the output and convert each line to UTF-16; and then pass them to out-file.
Surprisingly, this is also true when you type:
git show master:image.png > image-master.png
Execute this in a powershell prompt and a DOS prompt and the content of the file will be different. With a DOS prompt, it is working as expected, whereas Powershell screws up the content on the file. Basically, Microsoft broke backward compatibility on this particular topic...I wonder how this decision was taken internally...
After failing with ">", I tried all the possible options for cmdlet out-file . It does not work, period. By the way, Set-Content won't work either.
Now, I really needed to deal with binary output. I had to do something about it. It took me a couple of hours, a lot of reading on the web and I ended up with my own powershell function to do it. If you want to save the content of command1 in file.out ; execute:
saveBinary('file.out' command1)
If you need parameters for command1:
saveBinary('file.out' command1 parameter1 switch1)Here is the source code, I've been using it extensively and so far it works fine:
function execSaveBinary([string] $file, [string] $command) { $processname = $command.split(" ") | select-object -first 1 $ArgumentList = $command.split(" ") | select-object -skip 1 $process = New-Object System.Diagnostics.Process $process.StartInfo.FileName = (Get-Command $processname -totalcount 1).Definition $process.StartInfo.WorkingDirectory = (Get-Location).Path $process.StartInfo.Arguments = $argumentList $process.StartInfo.UseShellExecute = $false $process.StartInfo.RedirectStandardOutput = $true $process.StartInfo.RedirectStandardError = $true $process.Start() $fileStream = New-Object System.IO.FileStream($file, [System.IO.FileMode]'Create', [System.IO.FileAccess]'Write') $blockSize = 4096 $bytesRead = 0 $bytes = New-Object byte[] $blockSize do { $bytesRead = $process.StandardOutput.BaseStream.Read($bytes, 0, $blockSize) if($bytesRead -gt 0) { $fileStream.Write( $bytes, 0, $bytesRead) } } while($bytesRead -gt 0) $process.WaitForExit() $fileStream.Close() }
No comments:
Post a Comment