88

I have a PowerShell script to add a website to Trusted Sites in Internet Explorer:

set-location "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
set-location ZoneMap\Domains
new-item TESTSERVERNAME
set-location TESTSERVERNAME
new-itemproperty . -Name http -Value 2 -Type DWORD

I want to execute these PowerShell commands from a batch file. It seems simple when I have to run a single command, BUT in this case I have a sequence of related commands. I want to avoid creating a separate file for the PS script to be called from the batch - everything must be in the batch file.

How to execute PowerShell commands (or cmdlets) from a batch file?

1

7 Answers 7

140

This is what the code would look like in a batch file(tested, works):

powershell -Command "& {set-location 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings'; set-location ZoneMap\Domains; new-item SERVERNAME; set-location SERVERNAME; new-itemproperty . -Name http -Value 2 -Type DWORD;}"

Based on the information from:

http://dmitrysotnikov.wordpress.com/2008/06/27/powershell-script-in-a-bat-file/

Sign up to request clarification or add additional context in comments.

5 Comments

how I can split long lines ? lines similar to your example.
@JuanPablo Sorry for VERY late reply but only today made a commitment to review my stackoverflow usage and be more active. Did you get this answered?
Is it possible to pass multiple .ps1 files ?
Can you give an example? Sounds like another question.
for fun, #!/bin/bash powershell <<<'run this string' works, but its so. slow.
15

This solution is similar to walid2mi (thank you for inspiration), but allows the standard console input by the Read-Host cmdlet.

pros:

  • can be run like standard .cmd file
  • only one file for batch and powershell script
  • powershell script may be multi-line (easy to read script)
  • allows the standard console input (use the Read-Host cmdlet by standard way)

cons:

  • requires powershell version 2.0+

Commented and runable example of batch-ps-script.cmd:

<# : Begin batch (batch script is in commentary of powershell v2.0+)
@echo off
: Use local variables
setlocal
: Change current directory to script location - useful for including .ps1 files
cd %~dp0
: Invoke this file as powershell expression
powershell -executionpolicy remotesigned -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
: Restore environment variables present before setlocal and restore current directory
endlocal
: End batch - go to end of file
goto:eof
#>
# here start your powershell script

# example: include another .ps1 scripts (commented, for quick copy-paste and test run)
#. ".\anotherScript.ps1"

# example: standard input from console
$variableInput = Read-Host "Continue? [Y/N]"
if ($variableInput -ne "Y") {
    Write-Host "Exit script..."
    break
}

# example: call standard powershell command
Get-Item .

Snippet for .cmd file:

<# : 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...

3 Comments

Usage note: there are some edge cases where cd %~dp0 won't work, and this style of invocation will set $PSScriptRoot to null, because we're running as a series of commands instead of as a script. I've dropped the cd %~dp0 and changed the invoked expression to $($ScriptHome = '%~dp0'; [System.IO.File]::ReadAllText('%~dpf0')) to handle this.
Do I include the # in my powershell commands?
@JustinGoldberg - <# comment block for powershell #> - in this comment block is .bat/.cmd commands for powershell run, and after that comment block you can use any powershell syntax with a # :)
10

Type in cmd.exe Powershell -Help and see the examples.

Comments

6

untested.cmd

;@echo off
;Findstr -rbv ; %0 | powershell -c - 
;goto:sCode

set-location "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
set-location ZoneMap\Domains
new-item TESTSERVERNAME
set-location TESTSERVERNAME
new-itemproperty . -Name http -Value 2 -Type DWORD

;:sCode 
;echo done
;pause & goto :eof

Comments

4

When calling multiline PowerShell statements from a batch file, end each line with a caret, except the last line. You don't have to have the extra spacing at the beginning of the line, that's my convention.

PowerShell set-location "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" ^
           set-location ZoneMap\Domains ^
           new-item TESTSERVERNAME ^
           set-location TESTSERVERNAME ^
           new-itemproperty . -Name http -Value 2 -Type DWORD

If you are piping into a cmdlet like Select-Object, you need to terminate with a semicolon to end the command, otherwise it will include the next line.

Powershell $disk = Get-WmiObject Win32_LogicalDisk -Filter """"DeviceID='D:'"""" ^| Select-Object Freespace; ^
           Exit ([math]::truncate($disk.freespace / 1GB))

Comments

2

I couldn't get any answers to work, but adding @Hassan Voyeau's -Command and ;'s in tandem with @Ed Palmer's formatting made it work:

powershell -Command ^
More? set-location "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"; ^
More? set-location ZoneMap\Domains; ^
More? new-item TESTSERVERNAME; ^
More? set-location TESTSERVERNAME; ^
More? new-itemproperty . -Name http -Value 2 -Type DWORD

Here, ; tells powershell.exe being called that the current command-line ends there and more command-lines can be specified further while ^ tells CMD (for the sake of simplicity; it's actually called "Windows Script Host") that there may be more string input on the next line. From our perspective, CMD parses multiple command-lines into one command-line via CR/LF line-endings escape character ^ so that powershell.exe sees the one-line command-line -Command set-location ...; set-location ...; ... instead.

  • If you want to specify any powershell parameters, do so before -Command since powershell.exe interprets command-lines subsequent to -Command as -Command's single code-block argument. Using curly-braces to explicitly delimit the code block like -Command {set-location ...; ...} doesn't allow specifying powershell parameters afterward, e.g. -Command {...} -NoExit, either.
  • In this formatting, don't use " to delimit -Command's argument like @Hassan Voyeau's since CMD interprets ^ inside unclosed " as a literal caret character.
  • Using ^ as the first character on any line after the first line will also make CMD interpret it as a literal caret character. Use a whitespace before one to semantically designate an empty line instead.
  • If you want to include a comment between code, use PowerShell's block-comment <# .. #> (PowerShell's in-line comment # which denotes all subsequent characters as part of its comment can't be escaped since, again, ^ parses multiple command-lines into one command-line.) However, without " as in @Hassan Voyeau's to encapsulate < and >, CMD will parse them as I/O redirection operators which we can escape by using a prefixing-caret like ^<# COMMENT GOES HERE #^>. If you insert a block-comment on an empty line, ^ will become the first character of the line and will be interpreted as a literal caret character so we work around that like earlier by inserting a prefixing whitespace to get:
    ⋮
    More? COMMAND ARG1 ARG2 ...; ^<# IN-LINE BLOCK COMMENT #^> ^
    More?  ^<# SEPARATE-LINE BLOCK COMMENT #^> ^
    More? COMMAND ARG1 ARG2 ...;^<# NO PREFIXING/SUFFIXING SPACES REQUIRED #^>^
    ⋮
    
  • To escape characters in arguments, use PowerShell's escape character backtick/grave-accent `. Since backticks aren't one of its escape characters (^ for I/O redirection operators, \ for double-quotes, % for percent), CMD won't consume backticks.
    • If your arguments contains spaces but not escape characters, you can use single-quotes to delimit the argument. CMD will parse it as multiple arguments still since the spaces aren't delimited but PowerShell will correctly piece it back together with spaces reattached.
    • If your arguments contains escape characters, you can use double-quotes encapsulating CMD-escaped double-quotes or the other way around to commands. The unescaped double-quotes tell CMD that special characters within, e.g. spaces, mustn't be treated as argument separators while CMD-escaped double-quotes pass onto and are parsed by PowerShell as normal double-quotes. The escape character for double-quotes is \. (Quoting/Escaping 1/2) For instance:
    More? write-output 'there are spaces here'; ^
    More? write-output "\"new line`r`nhere\""; ^
    More? write-output \""also`r`nhere"\"; ^
    
    will result in:
    there are spaces here
    new line
    here
    also
    here
    

Comments

1

Looking for the possibility to put a powershell script into a batch file, I found this thread. The idea of walid2mi did not worked 100% for my script. But via a temporary file, containing the script it worked out. Here is the skeleton of the batch file:

;@echo off
;setlocal ENABLEEXTENSIONS
;rem make from X.bat a X.ps1 by removing all lines starting with ';' 
;Findstr -rbv "^[;]" %0 > %~dpn0.ps1 
;powershell -ExecutionPolicy Unrestricted -File %~dpn0.ps1 %*
;del %~dpn0.ps1
;endlocal
;goto :EOF
;rem Here start your power shell script.
param(
    ,[switch]$help
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.