I've struggled with NotebookEvaluate[] as well when run from a subkernel. One of my workarounds for simpler notebooks is to write my own "NotebookEvaluate" function:
1) read the raw form of the notebook using Get
2) replace every Input cell type with a sequence of Input and Output cells, where the Output cell has gone from its BoxForm, ToExpression, and back to BoxForm.
evaluateNotebook[loc_String] := Module[{test,nb},
UsingFrontEnd[
test=Get[loc];
nb=CreateDocument[test/.Cell[BoxData[x___],"Input",y___] :> Sequence[Cell[BoxData[x],"Input",y],Cell[BoxData[ToBoxes[ToExpression[BoxData[x]]]],"Output"]]];
NotebookSave[nb,loc];
NotebookClose[nb];
]
]
This will not overwrite older Output or warning messages, but you can add some rules to remove those, too, using empty sequences:
(*rule to remove old output cells*)
Cell[BoxData[___], "Output", ___] -> Sequence[];
(*rules to remove old message cells*)
Cell[BoxData[___], "Message", ___] -> Sequence[];
I'm not sure how robust this approach is, i.e. I haven't tested how it deals with cells that are commented out, but it does a good job for how short it is. I'm open to any feedback on improving it.