-1

Can we call Bat command within powershell without calling/invoking a bat file?

For example bat script:

@echo [off]
echo sample batch script
pause

In powershell itself

Commands must be executed.

Ole Morud
  • 157
  • 10
  • 2
    Batch commands aren't powershell commands (there are a few overlapping aliases, but the commands themselves are different), so I'm not sure what you're trying to do here. – SomethingDark Apr 13 '23 at 08:16

2 Answers2

2

You can emulate most things BATCH.

  1. For example PAUSE.
  2. And ECHO is similar to Write-Host and $Var | Out-Host.

Also, you can call BATCH commands with cmd.exe --% /c, BUT, as soon as cmd.exe exits, the environment the command was executed in is gone - along with any environment variables that were set.

On the other hand, cmd.exe's output can be saved to a variable.
In this example:

  1. Everything after the Stop-Parsing token is passed unprocessed to CMD.
  2. The path given to dir is dynamically provided by first setting an environment variable $Env:DirPath = 'C:\Users\public', and then retrieved the environment variable in BATCH %DirPath%.
  3. Uses $Var = $(<code>) to save output in $Var.

NOTE: The closing parentheses is NOT at the end of the cmd.exe --% line, because, if it was, it would be ignored by PowerShell.

$Env:DirPath = 'C:\Users\public'
$Var = $(
    cmd.exe --% /c dir "%DirPath%" /w
)
$Var

You should also be able to use & in the cmd.exe --% command to execute more than one BATCH command, but I haven't experimented with that, so not sure how that would work out.

Darin
  • 1,423
  • 1
  • 10
  • 12
  • 1
    Nicely done, but I suggest also mentioning `Write-Output`, not just `Write-Host`, in the context of `echo`. Note that while there are indeed many pitfalls with `--%`, a single-line `$Var = cmd.exe --% /c dir "%DirPath%" /w` would work fine. If you enclose everything after `/c` in `'...'`, you can avoid `--%` (except for potentially needing to escape embedded `'` as `''`, but even that can be avoided with a _here-string_). Similarly, `cmd /c "..."` allows direct use of PowerShell's string interpolation (though this mixing of the worlds may be harder to understand) – mklement0 Apr 13 '23 at 14:48
1
  • You cannot execute batch-file commands directly in PowerShell, because PowerShell doesn't understand them.

    • While there is a small subset of commands that have the same name in both cmd.exe (the interpreter of batch files) and PowerShell, by way of PowerShell providing aliases for its differently named commands (e.g., dir for Get-ChildItem), calls to these few commands only work the same in all but the simplest cases, given that PowerShell's parameter syntax differs fundamentally from that of cmd.exe
  • You can execute batch-file commands via cmd.exe's CLI, namely either via cmd /c (run cmd /? for details) or by piping commands to cmd.exe (... | cmd), but note the following:

    • Like batch files, such calls run in a child process, so that modifications to environment variables wouldn't be seen by the caller, for instances.

    • The commands are interpreted as in interactive cmd.exe sessions, which notably means that for loops must use %i rather than %%i, for instance.

    • Passing multiple batch-file commands has severe limitations:

      • With cmd /c, you can only pass a single line (any additional lines are ignored), so you must use cmd.exe's & operator to sequence multiple commands, which only works if these commands do not depend on each other with respect to variables.

         # OK - the two commands aren't interdependent.
         cmd /c 'ver & date /t'
        
         # !! NOT OK - the %FOO% value isn't seen by the echo call
         cmd /c '(Set FOO=bar) & echo %FOO%'
        
        • However, you can enable the delayed-variable-expansion feature via the /v option, in which case using !...! instead of %...% does work:

           # OK - thanks to /v and !FOO!
           cmd /v /c '(Set FOO=bar) & echo !FOO!'
          
        • Separately, you can use an expandable (double-quoted) string ("...") in order to embed the value of PowerShell variables in the cmd /c call, as an alternative to the --% technique shown in Darin's answer; if you need to embed " characters, escape them as `" (or ""):

           $foo = 'bar' # define a PowerShell variable
           cmd /c "echo $foo" # embed its value in the "..." string
          
      • With multiline pipeline input:

        • Even if you start your multiline input string with @echo off, you will invariably see cmd.exe's startup banner ( Microsoft Windows [Version ...]) and one prompt string (e.g, C:\>), and the source code line of each command will print either way before the result of its execution.

        • Unless the code exits with an explicit exit call, the cmd.exe's exit code will not reflect the exit code of the last command executed.

        • For more information as well as a helper function that creates a temporary batch file behind the scenes to avoid these limitations, see this answer

        • Here's an example that uses a here-string to feed multiple commands to cmd.exe; as noted, you'll see the startup banner and one prompt string, and the source-code lines will print before each command's output:

           @'
           @echo off
           ver
           date /t
           Set FOO=bar
           echo %FOO%
           exit
           '@ | cmd.exe
          
mklement0
  • 382,024
  • 64
  • 607
  • 775