Holy cow, I wrote a book!
(Employing the snowclone "What this X needs is more Y.")
Each time you add a parsing pass to the batch processor,
you have to
add another layer of escaping.
This is just a special case of the more general rule of thumb:
any problem in quoting can be solved by adding another layer of escaping.
(Okay, it's not actually true, nor is it a rule of thumb,
but it's still something to keep in mind.)
When you enable delayed variable expansion, you add another parsing
pass to the batch processor.
It used to expand % variables at the time the line is ready,
but now you told it that, oh wait, just before executing the
command, expand it a second time (this time looking for ! variables.)
The ^^ collapses to a ^ during the first
On the second parsing pass, the ^! turns into a !
the batch language was not designed; it evolved.
the approach taken by commenter Nick,
in a tip of the hat to Douglas Adams:
Much like the universe,
if anyone ever does fully come to understand Batch
then the language will instantly be replaced by an
infinitely weirder and more complex version of itself.
This has obviously happened at least once before ;)