如何在Windowsbatch file中运行PowerShell脚本

如何在Windows批处理脚本中embedded与PowerShell脚本相同的文件?

我知道这种事情在其他情况下是可能的:

  • 将SQLembedded到使用sqlcmd的批处理脚本中,并在文件开始处巧妙地安排了goto和注释
  • 在具有程序名称的* nix环境中,您希望在脚本的第一行中注释脚本,例如#!/usr/local/bin/python

可能没有办法做到这一点 – 在这种情况下,我将不得不从启动脚本调用单独的PowerShell脚本。

我考虑的一个可能的解决scheme是回显PowerShell脚本,然后运行它。 这样做的一个很好的理由是,尝试这样做的部分原因是要使用PowerShell环境的优势, 不必担心例如转义字符

我有一些不寻常的限制,希望find一个优雅的解决scheme。 我怀疑这个问题可能是这个品种的诱饵反应:“你为什么不尝试解决这个不同的问题呢?” 只要说这些是我的约束,对此感到遗憾。

有任何想法吗? 是否有巧妙的注释和转义字符的组合,使我能够实现这一点?

关于如何实现这个的一些想法:

  • 行尾的一个克拉^是一个延续 – 就像Visual Basic中的下划线一样
  • 和号&通常用于分隔命令echo Hello & echo World在单独的行中产生两个回波
  • %0会给你正在运行的脚本

所以这样的事情(如果我能做到的话)会很好:

 # & call powershell -psconsolefile %0 # & goto :EOF /* From here on in we're running nice juicy powershell code */ Write-Output "Hello World" 

除…

  • 这不起作用…因为
  • 该文件的扩展名不符合PowerShell的喜好: Windows PowerShell console file "insideout.bat" extension is not psc1. Windows PowerShell console file extension must be psc1. Windows PowerShell console file "insideout.bat" extension is not psc1. Windows PowerShell console file extension must be psc1.
  • CMD对于这种情况并不满意,虽然它在'#', it is not recognized as an internal or external command, operable program or batch file.上绊倒了'#', it is not recognized as an internal or external command, operable program or batch file.

这一个只传递给PowerShell的正确的线:

dosps2.cmd

 @findstr/v "^@f.*&" "%~f0"|powershell -&goto:eof Write-Output "Hello World" Write-Output "Hello some@com & again" 

正则表达式排除以@f开始的行,并包含一个& ,并将其他所有内容传递给PowerShell。

 C:\tmp>dosps2 Hello World Hello some@com & again 

这听起来像你正在寻找什么有时被称为“多语种脚本”。 对于CMD – > PowerShell,

 @@:: This prolog allows a PowerShell script to be embedded in a .CMD file. @@:: Any non-PowerShell content must be preceeded by "@@" @@setlocal @@set POWERSHELL_BAT_ARGS=%* @@if defined POWERSHELL_BAT_ARGS set POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"% @@PowerShell -Command Invoke-Expression $('$args=@(^&{$args} %POWERSHELL_BAT_ARGS%);'+[String]::Join([char]10,$((Get-Content '%~f0') -notmatch '^^@@'))) & goto :EOF 

如果你不需要支持引用的论点,你甚至可以把它作为一个单行的:

 @PowerShell -Command Invoke-Expression $('$args=@(^&{$args} %*);'+[String]::Join([char]10,(Get-Content '%~f0') -notmatch '^^@PowerShell.*EOF$')) & goto :EOF 

取自http://blogs.msdn.com/jaybaz_ms/archive/2007/04/26/powershell-polyglot.aspx 那是PowerShell v1; 在v2中可能会更简单,但我没看过。

这里已经讨论了这个话题。 主要目标是避免使用临时文件来减少IO操作的缓慢,并在没有冗余输出的情况下运行脚本。

根据我的说法,这是最好的解决方案:

 <# : @echo off setlocal set "POWERSHELL_BAT_ARGS=%*" if defined POWERSHELL_BAT_ARGS set "POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%" endlocal & powershell -NoLogo -NoProfile -Command "$input | &{ [ScriptBlock]::Create( ( Get-Content \"%~f0\" ) -join [char]10 ).Invoke( @( &{ $args } %POWERSHELL_BAT_ARGS% ) ) }" goto :EOF #> param( [string]$str ); $VAR = "Hello, world!"; function F1() { $str; $script:VAR; } F1; 

编辑 (更好的方式在这里看到)

 <# : batch portion (begins PowerShell multi-line comment block) @echo off & setlocal set "POWERSHELL_BAT_ARGS=%*" echo ---- FROM BATCH powershell -noprofile -NoLogo "iex (${%~f0} | out-string)" exit /b %errorlevel% : end batch / begin PowerShell chimera #> $VAR = "---- FROM POWERSHELL"; $VAR; $POWERSHELL_BAT_ARGS=$env:POWERSHELL_BAT_ARGS $POWERSHELL_BAT_ARGS 

其中POWERSHELL_BAT_ARGS是命令行参数,首先设置为批处理部分中的变量。

这似乎工作,如果你不介意一开始PowerShell中的一个错误:

dosps.cmd

 @powershell -<%~f0&goto:eof Write-Output "Hello World" Write-Output "Hello World again" 

没有完全理解你的问题,我的建议是这样的:

 @echo off set MYSCRIPT="some cool powershell code" powershell -c %MYSCRIPT% 

或更好

 @echo off set MYSCRIPTPATH=c:\work\bin\powershellscript.ps1 powershell %MYSCRIPTPATH% 

这支持与Carlos发布的解决方案不同的论点,并且不会破坏多行命令或像Jay发布的解决方案那样使用param 唯一的缺点是这个解决方案创建一个临时文件。 对于我的用例是可以接受的。

 @@echo off @@findstr/v "^@@.*" "%~f0" > "%~f0.ps1" & powershell -ExecutionPolicy ByPass "%~f0.ps1" %* & del "%~f0.ps1" & goto:eof