Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Windows批处理文件中运行PowerShell脚本_Windows_Powershell_Batch File_Cmd_Scripting - Fatal编程技术网

如何在Windows批处理文件中运行PowerShell脚本

如何在Windows批处理文件中运行PowerShell脚本,windows,powershell,batch-file,cmd,scripting,Windows,Powershell,Batch File,Cmd,Scripting,如何将PowerShell脚本嵌入到与Windows批处理脚本相同的文件中 我知道这种情况在其他情况下也是可能的: 使用sqlcmd在批处理脚本中嵌入SQL,并在文件开头巧妙地安排goto和注释 在*nix环境中,脚本的第一行注释掉了要运行脚本的程序的名称,例如,#/usr/local/bin/python 可能没有办法做到这一点-在这种情况下,我将不得不从启动脚本中调用单独的PowerShell脚本 我考虑过的一个可能的解决方案是回显PowerShell脚本,然后运行它。不这样做的一个很好

如何将PowerShell脚本嵌入到与Windows批处理脚本相同的文件中

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

  • 使用
    sqlcmd
    在批处理脚本中嵌入SQL,并在文件开头巧妙地安排goto和注释
  • 在*nix环境中,脚本的第一行注释掉了要运行脚本的程序的名称,例如,
    #/usr/local/bin/python
可能没有办法做到这一点-在这种情况下,我将不得不从启动脚本中调用单独的PowerShell脚本

我考虑过的一个可能的解决方案是回显PowerShell脚本,然后运行它。不这样做的一个很好的理由是,尝试这样做的部分原因是为了利用PowerShell环境的优势,而不必承受以下痛苦,例如

我有一些不寻常的限制,希望找到一个优雅的解决方案。我怀疑这个问题可能会引起各种各样的反应:“你为什么不试着去解决这个不同的问题呢?”我只想说这些是我的限制,对此我深表歉意

有什么想法吗?有没有巧妙的注释和转义字符的适当组合可以让我实现这一点

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

  • 一行末尾的克拉是一个延续,就像Visual Basic中的下划线一样
  • 符号
    &
    通常用于分隔命令
    echo Hello&echo World
    在单独的行上产生两个回音
  • %0将为您提供当前正在运行的脚本
所以像这样的东西(如果我能让它工作的话)会很好:

调用powershell-psconsolefile%0 #&转到:EOF /*从现在开始,我们将运行非常有趣的powershell代码*/ 写入输出“Hello World” 除了

  • 它不起作用。。。因为
  • 该文件的扩展名不符合PowerShell的要求:
    Windows PowerShell控制台文件“insideout.bat”的扩展名不是psc1。Windows PowerShell控制台文件扩展名必须为psc1。
  • CMD也并不完全满意这种情况——尽管它偶然发现了
    “#”,但它并没有被识别为内部或外部命令、可操作程序或批处理文件。

    • 如果不完全理解您的问题,我的建议如下:

      @echo off
      set MYSCRIPT="some cool powershell code"
      powershell -c %MYSCRIPT%
      
      或者更好

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

      如果您不介意PowerShell开始时出现一个错误,那么这似乎是可行的:

      dosps.cmd

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

      @powershell-此命令仅将正确的行传递给powershell:

      dosps2.cmd

      @powershell -<%~f0&goto:eof
      Write-Output "Hello World" 
      Write-Output "Hello World again" 
      
      @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
      

      摘自。那是PowerShell v1;在v2中可能更简单,但我没有看过。

      这支持参数,不像Carlos发布的解决方案,也不像Jay发布的解决方案那样中断多行命令或使用
      param
      。唯一的缺点是这个解决方案会创建一个临时文件。对于我的用例,这是可以接受的

      @@echo off
      @@findstr/v "^@@.*" "%~f0" > "%~f0.ps1" & powershell -ExecutionPolicy ByPass "%~f0.ps1" %* & del "%~f0.ps1" & goto:eof
      
      这个话题已经讨论过了。主要目标是避免使用临时文件,以减少缓慢的I/O操作,并在没有冗余输出的情况下运行脚本

      这是我认为最好的解决方案:

      <# :
      @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;
      
      
      param(
      [字符串]$str
      );
      $VAR=“你好,世界!”;
      函数F1(){
      $str;
      $script:VAR;
      }
      F1;
      
      更好的方法(见):

      
      $VAR=“----来自POWERSHELL”;
      $VAR;
      $POWERSHELL\u BAT\u ARGS=$env:POWERSHELL\u BAT\u ARGS
      $POWERSHELL\u BAT\u ARGS
      
      其中
      POWERSHELL\u BAT\u ARGS
      是批处理部分中首先设置为变量的命令行参数

      技巧在批次重定向优先级-这行<代码>

      也考虑,其中<强>支持嵌入式PuthSeBand和/或VBScript /JScript COD<强/E;这篇文章是作者本人在2013年发布的文章改编而成,但由于只是一个链接式的答案,它在2015年被删除。

      一种改进了以下方面的解决方案:

      创建包含以下内容的批处理文件(例如
      sample.cmd
      ):

      <# ::
      @echo off & setlocal
      copy /y "%~f0" "%TEMP%\%~n0.ps1" >NUL && powershell -NoProfile -ExecutionPolicy Bypass -File "%TEMP%\%~n0.ps1" %*
      set ec=%ERRORLEVEL% & del "%TEMP%\%~n0.ps1"
      exit /b %ec%
      #>
      
      # Paste arbitrary PowerShell code here.
      # In this example, all arguments are echoed.
      'Args:'
      $Args | % { 'arg #{0}: [{1}]' -f ++$i, $_ }
      
      产生如下结果:

      Args:
      arg#1:[值w/空格和特殊字符。(\|'),在Windows NT上]
      arg#2:[666]
      arg#3:[丽莎“左眼”洛佩兹]
      
      注意如何将嵌入的
      字符作为
      \”
      传递
      但是,有些边缘案例与嵌入式
      字符相关。

      :: # BREAKS, due to the `&` inside \"...\"
      sample.cmd "A \"rock & roll\" life style"
      
      :: # Doesn't break, but DOESN'T PRESERVE ARGUMENT BOUNDARIES.
      sample.cmd "A \""rock & roll\"" life style"
      
      这些困难都是由于
      cmd.exe
      的有缺陷的参数解析造成的,最终,试图隐藏这些缺陷是毫无意义的,如图所示

      正如他所解释的,
      \\“…\”
      序列中使用
      ^^
      (sic)转义以下
      cmd.exe
      元字符可以解决问题:

      & | < >
      

      我目前对该任务的偏好是一个polyglot头,其工作方式与:

      由于
      cmd.exe
      的参数解析毫无价值,这一点确实被打破了。我通常发现,我试图隐藏cmd的许多限制的工作越少,导致自己出现的意外错误就越少(例如,我确信我可以想出包含括号的参数,这些参数将打破mklement0在其他方面无可挑剔的符号和转义逻辑)。在我看来,咬紧牙关,使用类似

      sample.cmd "A \"rock ^^^& roll\" life style"
      
      第一个和第三个
      ^
      转义在最初解析该命令行时被吃掉;第二个幸存下来,以转义嵌入在命令行中的
      &
      <#  :cmd header for PowerShell script
      @   set dir=%~dp0
      @   set ps1="%TMP%\%~n0-%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.ps1"
      @   copy /b /y "%~f0" %ps1% >nul
      @   powershell -NoProfile -ExecutionPolicy Bypass -File %ps1% %*
      @   del /f %ps1%
      @   goto :eof
      #>
      
      # Paste arbitrary PowerShell code here.
      # In this example, all arguments are echoed.
      $Args | % { 'arg #{0}: [{1}]' -f ++$i, $_ }
      
      # BREAKS, due to the `&` inside \"...\"
      sample.cmd "A \"rock & roll\" life style"
      
      sample.cmd "A \"rock ^^^& roll\" life style"
      
      <# :# PowerShell comment protecting the Batch section
      @echo off
      :# Disabling argument expansion avoids issues with ! in arguments.
      setlocal EnableExtensions DisableDelayedExpansion
      
      :# Prepare the batch arguments, so that PowerShell parses them correctly
      set ARGS=%*
      if defined ARGS set ARGS=%ARGS:"=\"%
      if defined ARGS set ARGS=%ARGS:'=''%
      
      :# The ^ before the first " ensures that the Batch parser does not enter quoted mode
      :# there, but that it enters and exits quoted mode for every subsequent pair of ".
      :# This in turn protects the possible special chars & | < > within quoted arguments.
      :# Then the \ before each pair of " ensures that PowerShell's C command line parser 
      :# considers these pairs as part of the first and only argument following -c.
      :# Cherry on the cake, it's possible to pass a " to PS by entering two "" in the bat args.
      echo In Batch
      PowerShell -c ^"Invoke-Expression ('^& {' + [io.file]::ReadAllText(\"%~f0\") + '} %ARGS%')"
      echo Back in Batch. PowerShell exit code = %ERRORLEVEL%
      exit /b
      
      ###############################################################################
      End of the PS comment around the Batch section; Begin the PowerShell section #>
      
      echo "In PowerShell"
      $Args | % { "PowerShell Args[{0}] = '$_'" -f $i++ }
      exit 0
      
      PowerShell -c ^"Invoke-Expression ('^& {' + [io.file]::ReadAllText('%~f0') + '} %ARGS%')"
      
      PowerShell -c ^"Invoke-Expression ('^& {' + (get-content -raw '%~f0') + '} %ARGS%')"
      
      <# :# PowerShell comment protecting the Batch section
      @echo off
      :# Disabling argument expansion avoids issues with ! in arguments.
      setlocal EnableExtensions DisableDelayedExpansion
      
      :# Prepare the batch arguments, so that PowerShell parses them correctly
      set ARGS=%*
      if defined ARGS set ARGS=%ARGS:"=\"%
      if defined ARGS set ARGS=%ARGS:'=''%
      
      :# The ^ before the first " ensures that the Batch parser does not enter quoted mode
      :# there, but that it enters and exits quoted mode for every subsequent pair of ".
      :# This in turn protects the possible special chars & | < > within quoted arguments.
      :# Then the \ before each pair of " ensures that PowerShell's C command line parser 
      :# considers these pairs as part of the first and only argument following -c.
      :# Cherry on the cake, it's possible to pass a " to PS by entering two "" in the bat args.
      echo In Batch
      PowerShell -c ^"Invoke-Expression ('^& {' + (get-content -raw '%~f0') + '} %ARGS%')"
      echo Back in Batch. PowerShell exit code = %ERRORLEVEL%
      exit /b
      
      ###############################################################################
      End of the PS comment around the Batch section; Begin the PowerShell section #>
      
      echo "In PowerShell"
      $Args | % { "PowerShell Args[{0}] = '$_'" -f $i++ }
      exit 0