如何从批处理文件中执行PowerShell命令?

78

我有一个 PowerShell 脚本,可以将网站添加到 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

我想从批处理文件中执行这些PowerShell命令。当我只需要运行单个命令时,似乎很简单,但是在这种情况下,我有一系列相关的命令。我希望避免创建一个单独的文件,以便从批处理文件调用PS脚本 - 所有内容都必须在批处理文件中。

问题是:如何从批处理文件中执行PowerShell命令(或语句)?


另请参阅...https://dev59.com/O3I-5IYBdhLWcg3wCz7y - SteveC
7个回答

119

这是批处理文件中的代码样例(已测试,可正常运行):

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;}"

根据以下信息:

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


3
如何分割长行?类似于您的示例中的行。 - JuanPablo
@JuanPablo 对于非常晚的回复我很抱歉,但今天才做出了承诺,要审查我的stackoverflow使用情况并更加活跃。你得到答案了吗? - Hassan Voyeau
1
能否传递多个.ps1文件? - Ali123
你能举个例子吗?听起来像是另一个问题。 - Hassan Voyeau
1
对于娱乐,#!/bin/bash powershell <<<'run this string' 可以工作,但速度太慢了。 - ThorSummoner

11
这个解决方案与walid2mi类似(感谢灵感),但允许使用Read-Host cmdlet进行标准控制台输入。 优点:
  • 可以像标准的.cmd文件一样运行
  • 批处理和powershell脚本只需一个文件
  • powershell脚本可以是多行的(易于阅读脚本)
  • 允许标准控制台输入(通过标准方式使用Read-Host cmdlet)
缺点:
  • 需要powershell版本2.0以上
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 .

.cmd文件段落:

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

使用说明:有一些边缘情况下,cd %~dp0 不起作用,而这种调用方式会将 $PSScriptRoot 设置为 null,因为我们是作为一系列命令而不是脚本运行的。我已经删除了 cd %~dp0 并将被调用的表达式更改为 $($ScriptHome = '%~dp0'; [System.IO.File]::ReadAllText('%~dpf0')) 来处理这个问题。 - Tydaeus
我的PowerShell命令中是否包含**#**符号? - Justin Goldberg
@JustinGoldberg - <# PowerShell 的注释块 #> - 在这个注释块中是用于运行 PowerShell 的 .bat/.cmd 命令,之后你可以使用任何 PowerShell 语法带有 # :) - kapitanrum

10

输入cmd.exe,然后键入Powershell -Help并查看示例。


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

4

在从批处理文件调用多行 PowerShell 语句时,除了最后一行外,每行都要以 ^ 结尾。您不必在行开头有额外的空格,这是我的惯例。

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

如果您将管道传输到像Select-Object这样的cmdlet中,则需要以分号终止命令,否则它将包括下一行。
Powershell $disk = Get-WmiObject Win32_LogicalDisk -Filter """"DeviceID='D:'"""" ^| Select-Object Freespace; ^
           Exit ([math]::truncate($disk.freespace / 1GB))

1

我无法得到任何可行的答案,但是加入@Hassan Voyeau-Command;@Ed Palmer的格式配合使用可以使其正常工作:

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

这里,; 告诉 powershell.exe 被调用的当前命令行已经结束,并且可以在之后指定更多的命令行,而 ^ 则告诉 CMD(为了简化起见;它实际上被称为“Windows脚本宿主”)下一行可能会有更多的字符串输入。 从我们的角度来看,CMD通过CR / LF行尾转义字符^将多个命令行解析为一个命令行,以便 powershell.exe 看到单行命令行 -Command set-location ...; set-location ...; ...
  • 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
    

1

在寻找将PowerShell脚本放入批处理文件的可能性时,我发现了这个帖子。 walid2mi的想法对我的脚本没有百分之百的效果。但通过包含脚本的临时文件,它可以实现。以下是批处理文件的框架:

;@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
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接