Redirect Input and Output of Powershell.exe to Pipes in C++ Redirect Input and Output of Powershell.exe to Pipes in C++ powershell powershell

Redirect Input and Output of Powershell.exe to Pipes in C++


You passed string to wrong place:

CreateProcess(TEXT("C:\\Windows\\System32\\cmd.exe")

actually the first parameter should be NULL: CreateProcess(NULL, TEXT("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe")


Your main point of confusion seem to be around wide characters or byte characters. In classic ASCII strings, each character is one byte. Modern systems use Unicode, and the two most popular flavors are UTF-8 (popular on unix) and UTF-16 which most of the Windows API uses. Windows most often (always?) uses the little-endian variety, where the first byte is the lower 8 bits and the second byte is the upper 8 bits. In unicode, the first 127 codepoints are backward compatible with the first 127 characters of ASCII, so the letter "W" in ASCII is 0x57 and in UTF-16 it is 0x57 0x00.

You are mixing ReadFile with printf. ReadFile uses an explicit length for the buffer and bytes read, and so it can happily transfer UTF-16 as binary data. However, printf comes from an old tradition of ASCII strings that are terminated with a NUL byte. So from printf's perspective you are giving it a string of length 1 because the second byte is 0x00.

Have a look at this question about wide characters with printf to see what you should do differently.

By default, PowerShell writes UTF-16 to its console, where-as the old cmd.exe was still using ASCII strings. It turns out that PowerShell doesn't use it's input handle at all though, unless you pass the option -Command -. With that option however, it switches back to ASCII strings for output and input. So, all you really need to do is pass that command line option, and things should start working just like for Cmd.exe.

I was working on a perl module for this, not C++, but you might find my source code helpful.

BTW, I'm disturbed by the other mis-information on this page:

  • In Windows, Pipe handles, Console handles, and File handles each have different behavior and are not "all pipes". It is valid to say they are all Handles, and that you can read/write to each of them and use them for stdin/stdout/stderr of a program.

  • while(1) { if (!condition) break; ... }is absolutely functionally equivalent towhile(condition) { ... }and there is no reason to avoid it aside from style. If your condition doesn't comfortably fit in a one-line expression it is perfectly reasonable to use while(1).

  • You should NOT set the first argument of CreateProcess to NULL because it un-ambiguously tells windows which program you intend to execute. If you pass it in the second argument then you need to make sure it is quoted properly because a path with a space in it could run a different program than intended or even become a security bug. You don't have to use the first argument, but do it if you can.