12

I want to pass several lines of code from a batch file to powershell.exe as -command parameter.

For example, code like this:

SET LONG_COMMAND=
if ($true)
{
Write-Host "Result is True"
}
else
{
Write-Host "Result is False"
}

START Powershell -noexit -command "%LONG_COMMAND%"

I would like to do it without creating a PowerShell script file, only a batch file.
Is it possible?

Thanks.

mcu
  • 2,622
  • 7
  • 32
  • 58

4 Answers4

17

You can add ' ^' to continue the string that you are assigning to a variable. This creates the command as a single line, so you need to use ';' between statements:

@ECHO off
SET LONG_COMMAND= ^
if ($true) ^
{ ^
Write-Host "Result is True"; ^
Write-Host "Multiple statements must be separated by a semicolon." ^
} ^
else ^
{ ^
Write-Host "Result is False" ^
}

START Powershell -noexit -command %LONG_COMMAND%

If the only code you need to execute is PowerShell, you can use something like:

;@Findstr -bv ;@F "%~f0" | powershell -command - & goto:eof

if ($true){
    Write-Host "Result is True" -fore green
}
else{
    Write-Host "Result is False" -fore red
}

Start-Sleep 5

which pipes all lines not starting with ";@F" to PowerShell.

Edit: I was able to start PowerShell in a separate window and allow cmd to exit with this:

@@ECHO off
@@setlocal EnableDelayedExpansion
@@set LF=^


@@SET command=#
@@FOR /F "tokens=*" %%i in ('Findstr -bv @@ "%~f0"') DO SET command=!command!!LF!%%i
@@START powershell -noexit -command !command! & goto:eof

if ($true){
    Write-Host "Result is True" -fore green
}
else{
    Write-Host "Result is False" -fore red
}

Note that there must be 2 spaces after setting the 'LF' variable since we are assigning a line feed to the variable.

Rynant
  • 20,554
  • 4
  • 53
  • 69
  • I think your second example is exactly what I was looking for. What is the significance of ;@ in a batch file? Thanks. – mcu Feb 21 '12 at 02:20
  • 1
    The `@` tells cmd not to echo the line as it executes. The `;` is just a parameter delimiter; `,` or `=` could also be used. It just reduces the chance that something else in file would match the string that is being filtered out. The line can start with `@` and any combination of `;`, `=` or `,`. Examples: `;;@`, `@,`, `==@,;`, etc. – Rynant Feb 21 '12 at 14:39
  • This works great. There is only one MINOR disadvantage. By starting the powershell in this way, I have two processes running: powershell.exe and cmd.exe. Also, there is no powershell prompt at the window. Is it possible to "start" the powershell.exe and exit cmd.exe? – mcu Feb 21 '12 at 18:43
  • Hmm, I think in the latest example the EnableDelayedExpansion might interfere with exclamation points inside the powershell code. If I change "Result is True" to "Result is True!", the exclamation point is not displayed. Otherwise, it works beautifully. – mcu Feb 22 '12 at 02:07
  • Do we need delayed expansion on %%i ? – mcu Feb 22 '12 at 03:02
  • 1
    Yeah, I didn't think about it causing a problem with the exclamation points. Jay Bazuzi has a good answer on embedding PowerShell in a batch file. I would replace `join(';'` with `join([char]10` in his script, and you can change it to `START` powershell and add `-noexit` The script also handles arguments: http://stackoverflow.com/a/2611487/291709 – Rynant Feb 22 '12 at 16:10
6

Use

start powershell -NoExit -EncodedCommand "aQBmACAAKAAkAHQAcgB1AGUAKQAKAHsACgBXAHIAaQB0AGUALQBIAG8AcwB0ACAAIgBSAGUAcwB1AGwAdAAgAGkAcwAgAFQAcgB1AGUAIgAKAH0ACgBlAGwAcwBlAAoAewAKAFcAcgBpAHQAZQAtAEgAbwBzAHQAIAAiAFIAZQBzAHUAbAB0ACAAaQBzACAARgBhAGwAcwBlACIACgB9AAoA"

Quoting from powershell /?

# To use the -EncodedCommand parameter:
$command = 'dir "c:\program files" '
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand

You can use a command that would otherwise require awkward escaping via -EncodedCommand by simply supplying a Base64-encoded string.

Joey
  • 316,376
  • 76
  • 642
  • 652
  • I think I misspoke. I meant: "I would like to do it without creating a PowerShell script file, only a batch file." So, how do I encode all this powershell code in a batch file? – mcu Feb 20 '12 at 18:12
  • I think you misread. See the first line of code above. The rest of the code is just quoted from the help and shows you how to *create* such an encoded command string. – Joey Feb 20 '12 at 18:25
  • OK, but how do I come up with that encoded string in a batch file? Thanks. – mcu Feb 20 '12 at 19:21
  • As a 1-time setup, you would run from PowerShell commandline or PS1 command something similar to the second bit of code that Joey provides. This converts the multi-line script into a single encoded string. Once you've generated that string once, from then on you can simply use the encoded version as a one-liner. This accomplishes what you're looking for, but unfortunately it obscures the intent when you look at the 1-liner. – Daniel Richnak Feb 20 '12 at 19:39
  • Yeah, the command changes. I was hoping to use this batch file as a template, so I only had to change the value of LONG_COMMAND variable and be done. I guess I could write a utility to generate that encoded string and paste it into the batch file, but it would be less clear. – mcu Feb 20 '12 at 19:54
1

You could use -Command - which causes ps to read it's commands from stdin. Put your commands in a file, and invoke

powershell -Command - <myCommandFile
wmz
  • 3,525
  • 1
  • 12
  • 21
  • This would probably work, but it still requires an extra file. I would the batch file to be self-contained. Thanks. – mcu Feb 20 '12 at 19:19
  • In that case you can just use `-File` which is easier. – Joey Feb 20 '12 at 19:32
  • @Joey I think running a script (as with -File) is different to running commands from security perspective, but I may be wrong, I'm not PS expert. – wmz Feb 20 '12 at 19:41
  • Hm, haven't played with execution policy in a long time. Maybe – Joey Feb 20 '12 at 19:47
1

The way of Joey is foolproof, but you could also use a simple multiline command in your case

The empty lines are necessary here (like in the LF sample of Rynant)

powershell -command if ($true)^

{^

Write-Host "Result is True"^

}^

else^

{^

Write-Host "Result is False"^

}

Here is an explanation of Long commands split over multiple lines

Community
  • 1
  • 1
jeb
  • 70,992
  • 15
  • 159
  • 202