Strange redirect in Batch/Powershell polyglot

batch-file, cmd, powershell, windows

Solution

"...running a bat file is parsed as if each line were manually entered."

No, parser rules are sometimes different between command line and batch file and in this case the difference is critical.

It complains about `#` being an invalid file in command line, and not in batch file, because the `<# :` construct is (to the batch parser) just a redirected label. The same kind of label you use in `goto :label` or `call :label`.

That means that the redirection, that is not executed in batch file as the "command" associated to the redirection is a label, is executed in command line as you can not have a label in a command line.

Problem

While attempting to rewrite a batch file, I was looking into the possibility of using powershell. The main issue that I had with it was that `.ps1` files aren't executable by default. I found a solution here, which I'll copy below, but I'm very confused about the syntax on the first line: ``` <# : batch script @echo off setlocal cd %~dp0 powershell -executionpolicy remotesigned -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))" endlocal goto:eof #> # here write your powershell commands... ``` Here's what I know from testing: - The space between `<#` and `:` is required, though there can be multiple. - It can also have a number 0-9 beforehand, such as `3<# :`, which makes me suspect that there's some weirdness involving redirects and labels. - The text after the colon is ignored and not necessary - If I add a command before it, such as `git <# : batch script`, the shell shows that it tried to evaluate `git : batch script 0<#` and can't find the file specified - Changing the `#` to a valid filename makes the complaint go away (naturally) - Attempting to run the line in an interactive session actually causes it to complain about not being able to find the file specified, but running it from a script (even if it's the only line in the `.cmd` file) silently succeeds That last bullet is the part I'm trying to figure out. What's different about the environments? My understanding was that part of the issue was that running a bat file is parsed as if each line were manually entered. Why doesn't it complain about `#` being an invalid file when called via a script?

Original source

Related problems