Win XP - то же поведение. До 4KB способ MSDN читает, после - виснет. Продвинутый способ работает хорошо, тестировались размеры буфера до 3 MB (42 сек. на Intel E7200) 
Реального использования "дочитывания" буфера в продвинутом способе замечено не было.
Решил помониторить объемы считывания с хронометражом. Одна строка нулей читалась, как можно догадаться, все время одним куском. Для приближения к реальности дописал генератор строк случайной длины из случайных символов. Вот код:
// размер буфера в байтах
var n = Math.floor(1024 * 3);
var sNL = "\n"; //Символ(ы) переноса строки
// вывод заданного количества символов
// количество опеделяется переменной n
if (WScript.Arguments.Named.Exists('INIT')) {
//var s = new Array(n + 1).join('0'); //Было
var nLinesCount = 0;
var nNewLineLen;
var s = "";
while (s.length < n) {
nNewLineLen = Math.floor(Math.random() * 400); //Случайная длина строки 0...399 символов
var ss = ""; //Строчка, заканчивающаяся переносом
for ( var i = 0; i < nNewLineLen; i++) {
var nCode = Math.floor(Math.random() * (123 - 33)) + 33; //Латинские + точки-звездочки-и-тд.
ss += String.fromCharCode(nCode);
}
s += ss + sNL;
nLinesCount++;
}
s = s.substring(0, n);
WScript.StdOut.Write(s);
WScript.Quit(nLinesCount);
}
// внутренняя команда вывода
var cmd = 'cscript //nologo ' + WScript.ScriptName + ' /INIT';
var sh = new ActiveXObject('WScript.Shell');
var ex = sh.Exec(cmd);
// массив для заполнения данными внутреннего скрипта
var result = [], times = [];
var t = new Timer();
if (WScript.Arguments.Named.Exists('ADV')) {
// "расширенный алгоритм
while (ex.Status == 0) {
if (ex.StdOut.AtEndOfStream) {
break;
}
result.push(ex.StdOut.ReadLine());
t.Stop();
times.push(t + " " + result[result.length - 1].length + " символов");
}
while (!ex.StdOut.AtEndOfStream) {
result.push(ex.StdOut.ReadLine());
t.Stop();
times.push("дочитывание " + t + " " + result[result.length - 1].length + " символов");
}
}
else {
// стандартный алгоритм (взят из документации MSDN)
while (ex.Status == 0) {
WScript.Sleep(100);
}
while (!ex.StdOut.AtEndOfStream) {
result.push(ex.StdOut.ReadLine());
t.Stop();
times.push(t + " " + result[result.length - 1].length + " символов");
}
}
// Вывод статуса внутреннего процесса и размера буфера
//vard(result, "Считанные блоки"); //Посмотреть генерируемый текст :)
vard(times, "Хронология чтений");
WScript.Echo("Скрипт-генератор " + (ex.Status ? ("завершен, сгенерировано строк: " + ex.ExitCode) : "не завершен"));
WScript.Echo("Символов прочтено " + result.join(sNL).length);
t.Stop();
WScript.Echo("Конец работы " + t);
//=== DEBUG_STUFF ==========================================================
/** Возвращает строку рекурсивного описания содержимого объекта oBj
* @param sParentName - имя объекта, произвольное, по сути комментарий (можно опустить)
* @param nEsting - максимальный уровень вложенности объектов/значений (можно опустить)
*/
function vardump(oBj, sParentName, nEsting) {
var sNL = "\r\n"; // Перенос строки
var nEsting_max = 12; //Максимальный исследуемый уровень вложенности, против бесконечных ссылок на самого себя
var nPadding = 2; //Структурный отступ сдвига потомков относительно родителей, в пробелах
//Ограничивать ли слишком длинное отображение объекта в поле >значения<
var bRestrictObjectVal = true, nRestrictWidth = 80, sCutSign = "...";
var bShowOnlyOwnProps = false; //Показывать только собственные (уникальные) свойства объекта или все приобретенные
var bShowFunctionsCode = false; //Показывать ли код функций
if (sParentName == undefined) sParentName = "";
if (isNaN(parseInt(nEsting))) nEsting = nEsting_max;
var sRes = "";
for ( var i = 0; i < nPadding * (nEsting_max - nEsting); i++)
sRes += " ";
if (nEsting >= 0) {
var sPrototype = Object.prototype.toString.call(oBj); //[object НекийТип], вызов через ***
sRes += sParentName + " ";
switch (typeof oBj) { //Описание элемента toString() и обрамление в соответствии с его типом
case "string":
sRes += "\"" + oBj + "\"";
break;
case "function":
if (sPrototype == "[object RegExp]") sRes += oBj + " as function"; //В Chrome typeof => function
else {
var s = "" + oBj;
var nIdx = s.indexOf(")") + 1;
if (nIdx) s = s.substring(0, nIdx);
else
s = "function"; //Не должно произойти
sRes += s;
}
break;
case "object":
if (Object.prototype.toString.call(oBj) == "[object Array]") { //Для массива - еще длину
sRes += "Array[" + oBj.length + "] ";
}
if (Object.prototype.toString.call(oBj) == "[object Date]" //Объекты с простым и информативным содерж. toString()
|| Object.prototype.toString.call(oBj) == "[object RegExp]") {
sRes += oBj;
}
else { //Вывод прочих объектов и массивов
sRes += ">";
var sOTS = ("" + oBj).replace(/\r/g, "\\r").replace(/\n/g, "\\n");
if (bRestrictObjectVal) { //Если надо, подрезаем слишком длинные описания в строку
var nMaxOTSLength = nRestrictWidth - sRes.length - 1; //-1 под "<"
var nCutOSTLength = nMaxOTSLength - sCutSign.length;
if (nCutOSTLength < 0) nCutOSTLength = 0; //Ну да, вылезет...
if (sOTS.length > nMaxOTSLength) sOTS = sOTS.substr(0, nCutOSTLength) + sCutSign;
}
sRes += sOTS + "<";
}
break;
default: //числа, спецзначения, логические
sRes += oBj;
}
sRes += sNL;
//Вывод содержимого объекта: строками следующего уровня иерархии
var sEl;
var sGetChildName =
function(oParent, sParentName, sChildName) { //Формирование имени потомка
var sFullChildName = sParentName;
var bIsIndex = false;
if (Object.prototype.toString.call(oParent) == "[object Array]") {
var nIdx = parseInt(sChildName, 10);
if (!isNaN(nIdx) && nIdx.toString() === sChildName.toString() && nIdx >= 0 && nIdx < oParent.length)
bIsIndex = true;
}
if (bIsIndex) sFullChildName += "[" + sChildName + "]";
else {
if (sFullChildName != "") sFullChildName += "."; //Если есть что отделять, отделяем точкой
sFullChildName += sChildName;
}
return sFullChildName;
}; //sGetChildName
if (Object.prototype.toString.call(oBj) == "[object RegExp]") { //В завис. от браузера typeof то object, то function
sEl = "lastIndex";
sRes += arguments.callee(oBj[sEl], sGetChildName(oBj, sParentName, sEl), nEsting - 1);
}
else { //Осмотрим внутренности
switch (typeof oBj) {
case "object": //Объекты и массивы
if (!oBj) break; //null
for (sEl in oBj) {
if (bShowOnlyOwnProps && !oBj.hasOwnProperty(sEl)) break;
sRes += arguments.callee(oBj[sEl], sGetChildName(oBj, sParentName, sEl), nEsting - 1);
}
break;
case "function":
if (bShowFunctionsCode) sRes += ">>>" + sNL + oBj + "<<<" + sNL;
break;
//Остальное содержимого не имеет
}
}
}
else
sRes += sParentName + " ! Nesting limit !" + sNL;
return(sRes);
}
/** Echo-обертка
*/
function vard() {
WScript.Echo(vardump.apply(null, arguments));
}
/** Класс замеров временных промежутков ------------------------------------
*/
function Timer() {
this.StartTime = this.StopTime = new Date(); //Сразу начинает отсчет
//--- Методы
/** Начинает отсчет, возвращает дату начала
*/
this.Start = function() {
return this.StartTime = this.StopTime = new Date();
};
/** Отмечает конечную точку отсчета (при этом по сути отсчет не останавливается), возвращает дату конца
*/
this.Stop = function() {
return this.StopTime = new Date();
};
/** Возвращает время (мс) между StartTime и StopTime
*/
this.Interval = function() {
return this.StopTime - this.StartTime;
};
/** Возвращает текстовое представление интервала "чч:мм:сс.мсс"
*/
this.toString = function() {
var nInt = this.Interval();
var aInt = [0, 0, 0, 0]; //Период поделенный на мс, с, м, ч
var aDivs = [1000, 60, 60, 10000000]; //Делители
var aDelims = [".", ":", ":", ""]; //Разделители
for ( var i = 0; i < 4; i++) {
aInt[i] = nInt % aDivs[i];
if (aInt[i] == nInt) break; //Все поделено
nInt = Math.floor(nInt / aDivs[i]);
}
var sInt = "";
for ( var i = 0; i < 4; i++)
sInt = aDelims[i] + sLeadingSigns(aInt[i]) + sInt;
return sInt;
};
/** Дополняет текстовое представление oBj знаками sSign (по ум. нулями) до длины nOutLength.
* Минус выносится вперед, если не выставленно bDoNotMinusMove
*/
function sLeadingSigns(oBj, nOutLength, sSign, bDoNotMinusMove) {
if (sSign == undefined) sSign = "0";
sSign = "" + sSign;
nOutLength = parseInt(nOutLength, 10);
if (isNaN(nOutLength) || nOutLength < 1) nOutLength = 2; //По ум.
var sObj = "" + oBj;
if (sObj.length < nOutLength) { //Если надо удлинять
var nZeros = nOutLength - sObj.length;
var sZeros = "";
for ( var i = 0; i < nZeros; i++)
sZeros += sSign;
return bDoNotMinusMove ? sZeros + sObj : sObj.replace(/(\-{0,1})(.+)/, "$1" + sZeros + "$2");
}
else
return sObj;
}
} //Timer()
Как можно видеть, все читается четко построчно: сколько строк выдано, столько раз и ReadLine(). Собсно, как и ожидалось в теории.
А вся затея с хронометражом произошла из-за желания понять особенности чтения и решить задачу чтения вывода приложения, которое может зависнуть, с возможностью его принудительного завершения по таймлимиту или по результатам чтения вывода. А тут как раз родственная тема! 
Надеюсь, из приведенного примера вполне удастся такое соорудить. Странно: раньше пример делал, вроде бы пока стороннее приложение не отрабатывало полностью, оно StdOut.AtEndOfStream не включало. А здесь включает после каждой строки.
Надо перепроверить...