How to execute PowerShell commands from a batch file?
I have a PowerShell script to ad开发者_C百科d a website to a 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.
The question is: How to execute PowerShell commands (or statements) from a batch file?
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/
Type in cmd.exe Powershell -Help
and see the examples.
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...
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
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))
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
)
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 specifyingpowershell
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 - 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:
will result in:More? write-output 'there are spaces here'; ^ More? write-output "\"new line`r`nhere\""; ^ More? write-output \""also`r`nhere"\"; ^
there are spaces here new line here also here
精彩评论