(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.)
Which means that if you want to echo an exclamation point, you have to protect the exclamation point so the parser won’t treat it as a delayed expansion.
^^ collapses to a
^ during the first
On the second parsing pass, the
^! turns into a
Remember, the batch language was not designed; it evolved. I admire 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 ;)