Работает как положено.
Отсроченное расширение будет расширять переменные во время выполнения, а не во время разбора, поэтому оно интерпретирует вашу строку ENDLOCAL & SET S1=!S2!
как
endlocal
Но в части SET S1=!S2!
отложенное расширение отключено, поэтому его нельзя больше расширять.
В вашем случае вы могли бы использовать
ENDLOCAL & SET S1=%S2%
Поскольку восклицательный знак S2 является «безопасным», то есть задержанный эксп. выключен в момент исполнения.
Но всегда безопасное возвращение немного сложнее.
Мы обсуждали это в Dostips: вернуть ЛЮБУЮ строку через ENDLOCAL границу