Upon a failed redirection (due to a non-existent file or insufficient file access), the ErrorLevel value seems not to be set (in the following examples, file test.tmp is write-protected and file test.nil does not exist):
>>> (call ) & rem // (reset `ErrorLevel`)
>>> > "test.tmp" echo Text
Access is denied.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
>>> (call ) & rem // (reset `ErrorLevel`)
>>> < "test.nil" set /P DUMMY=""
The system cannot find the file specified.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
However, as soon as the failed redirection is followed by the conditional concatenation operator ||, which is querying the exit code, the ErrorLevel becomes set to 1, unexpectedly:
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (> "test.tmp" echo Text) || echo Fail
Access is denied.
Fail
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=1
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (< "test.nil" set /P DUMMY="") || echo Fail
The system cannot find the file specified.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=1
Interestingly, ErrorLevel remains 0 when the operator && is used:
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (> "test.tmp" echo Text) && echo Pass
Access is denied.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (< "test.nil" set /P DUMMY="") && echo Pass
The system cannot find the file specified.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
ErrorLevel remains also 0 using the operator &:
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (> "test.tmp" echo Text) & echo Pass or Fail
Access is denied.
Pass or Fail
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (< "test.nil" set /P DUMMY="") & echo Pass or Fail
The system cannot find the file specified.
Pass or Fail
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
In case both conditional concatenation operators && and || appear, ErrorLevel is set to 1 too (if || occurs before &&, both branches are executed as in the last example, but I think this just because && evaluates the exit code of the preceding echo command):
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (> "test.tmp" echo Text) && echo Pass || echo Fail
Access is denied.
Fail
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=1
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (< "test.nil" set /P DUMMY="") || echo Fail && echo Pass
The system cannot find the file specified.
Fail
Pass
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=1
So what is the connection between the ErrorLevel value and the || operator, why is ErrorLevel affected by ||? Is || copying the exit code to ErrorLevel? Is all this only possible with (failed) redirections, because such are handled before any commands are executed?
Even more strangely, I could not observe the opposite behaviour -- ErrorLevel being reset to 0 by && --, when correctly reverting the test setup (that is, replacing (call ) by (call) (to set ErrorLevel to 1 initially), clearing the read-only attribute of file test.tmp, creating file test.nil (first line not empty to avoid set /P to set ErrorLevel to 1), and using file extension .bat rather than .cmd for testing (to avoid set /P to reset ErrorLevel to 0)).
I observed the described behaviour on Windows 7 and Windows 10.