Capture of exit status as a return value can be handled directly in DurableTaskStep.Execution, by simply returning Integer rather than returning void or throwing AbortException.
Capture of standard output is a little trickier because we would like to continue to direct standard error to the build log, and durable-task controllers currently mix them in the same stream. The API likely needs to be changed so that when launching the process you can request separate streams. (jenkins-out.txt vs. jenkins-err.txt I suppose, and two log position fields.) DurableTaskStep.Execution could then maintain a ByteArrayOutputStream-like buffer (but Serializable) collecting the output to be returned. Alternately, the controller could just return the complete standard output when the process exits, alongside the status code, which would make for a simpler API change, under the assumption that future clients do not want to stream output.
Likewise, sending standard input would require an API addition in durable-task. Streaming the input would be very awkward for a durable task (providing an InputStream is not possible) so you would probably have to provide the byte content up front.
Both API changes could potentially be avoided by just making DurableTaskStep.Execution modify the script to use redirects as shown in the workarounds here, using a random temporary file. There are some tricky parts here, too, though: the file ought to be outside the workspace to avoid clashes with scripts which expect to “own” the whole directory tree (cf. discussion in
JENKINS-27152); and to handle multiline scripts, or even scripts with shebangs (#!/usr/bin/python), you really need to save the user-provided script into another temporary file, then do a little dance to make it into a complete executable that could be called from the redirecting wrapper script (and here cf. JENKINS-29877).
Useful also for bat. According to answers here, Bourne shell syntax works for batch scripts too.