The 8191
-character limit applies to the interactive command line and calls to cmd.exe
's CLI (via cmd /c
)
It does not apply to commands invoked from batch files - there the limit is close to[1] 32KiB
(32,768
) characters.
- However, it still seems to apply selectively to
cmd.exe
's internal commands, such as echo
; by contrast, a call to an external program such as powershell.exe
is not affected (though it is possible for specific external programs to have their own, lower limits).
As an aside:
As clever as the linked method of converting PowerShell scripts to batch files is, the resulting batch files lack support for arguments to be passed through to the PowerShell code, and adding support for that would be impractical (it would require Base64-encoding the arguments too, at invocation time, which isn't possible from a batch file except with the help of non-built-in utilities).
If your script / batch file is written to either require no arguments on invocation or to prompt for them interactively (as in your case), this limitation is not a concern.
However, you may want argument support for any of the following reasons:
- To allow calling the batch file from
cmd.exe
(Command Prompt) with arguments.
- To allow calling with arguments from other environments that support passing arguments, notably Task Scheduler and the Windows
Run
dialog (WinKey-R).
- To make the batch file support drag-and-drop (which implicitly passes the dropped files' paths as arguments).
As for the overall reason to wrap PowerShell code in batch files:
- Batch files (
.cmd
, .bat
) can be launched directly, as if they were executables, system-wide.
- By contrast, this is not supported for PowerShell scripts (
.ps1
), which from outside PowerShell must be invoked via an explicit call to the PowerShell CLI; note that systems may be configured to categorically prevent execution of .ps1
scripts - see next section.
If you do need argument support in your batch file, the best - but inconvenient - solution is to distribute two files:
- the original
*.ps1
file...
- and a companion batch file, with the same base file name, to be placed in the same directory - which can be invoked from outside PowerShell - whose sole purpose is to invoke the
*.ps1
file via powershell.exe
with pass-through arguments.
E.g. foo.cmd
would accompany foo.ps1
, with the following - invariant - content:
@powershell.exe -NoProfile -File "%~dpn0.ps1" %*
Note:
Important: The above assumes that the effective PowerShell execution policy allows execution of script files (.ps1
).
- If you cannot make this assumption, place
-ExecutionPolicy RemoteSigned
before -NoProfile
above (or, to deactivate all checks, -ExecutionPolicy Bypass
), but note that an execution policy based on GPO (Group Policy Objects) may still prevent script execution.
To call PowerShell (Core) 7+ instead, use pwsh.exe
instead of powershell.exe
.
%~dpn0
expands to the full path of the enclosing batch file itself without its filename extension; appending .ps1
therefore targets the companion PowerShell script in the same directory; run cmd /c call /?
for an explanation of the syntax.
%*
passes any and all arguments received by the batch file on.
[1] In practice, the limits appear to be: 32,767
characters in batch files, and - lower by 3 chars. - 32,764
for Powershell (both on the command line / via the CLI and in *.ps1
scripts). In PowerShell, the limit may in practice be even lower than that, because PowerShell expands the names of executables it locates via $env:PATH
to their full paths in the command lines constructed behind the scenes, which cmd.exe
doesn't do.