【问题标题】:How to call batch script from Powershell?如何从 Powershell 调用批处理脚本?
【发布时间】:2011-05-22 01:15:59
【问题描述】:

我有一个设置大量环境变量的大批量脚本。 我想从 powershell 调用该批处理脚本,这样我可以同时受益,即我的脚本和 powershell 设置的环境变量。

【问题讨论】:

    标签: powershell batch-file


    【解决方案1】:

    如果你抓住PowerShell Community Extensions,其中有一个运行批处理文件的 Invoke-BatchFile 命令,但更重要的是,它保留了批处理文件所做的任何环境变量修改,例如:

    >Invoke-BatchFile 'C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat'
    Setting environment for using Microsoft Visual Studio 2008 x86 tools.
    

    【讨论】:

    • 自我说明,如下, 1.要从codeplex上的zip文件安装,右键单击并出现一个模式按钮,“取消阻止”出现;点击它。 2.解压后解压,然后按照$PSHome\Modules将文件夹放在你的模块位置。 stam.blogs.com/8bits/2010/06/…
    【解决方案2】:

    这个想法来自这篇博文:Nothing solves everything – PowerShell and other technologies

    这是我的脚本版本。它调用一个批处理文件(或任何 native 命令)并传播其环境:


    更新:此脚本的改进和更好的测试版本在这里:Invoke-Environment.ps1

    <#
    .SYNOPSIS
        Invokes a command and imports its environment variables.
    
    .DESCRIPTION
        It invokes any cmd shell command (normally a configuration batch file) and
        imports its environment variables to the calling process. Command output is
        discarded completely. It fails if the command exit code is not 0. To ignore
        the exit code use the 'call' command.
    
    .PARAMETER Command
            Any cmd shell command, normally a configuration batch file.
    
    .EXAMPLE
        # Invokes Config.bat in the current directory or the system path
        Invoke-Environment Config.bat
    
    .EXAMPLE
        # Visual Studio environment: works even if exit code is not 0
        Invoke-Environment 'call "%VS100COMNTOOLS%\vsvars32.bat"'
    
    .EXAMPLE
        # This command fails if vsvars32.bat exit code is not 0
        Invoke-Environment '"%VS100COMNTOOLS%\vsvars32.bat"'
    #>
    
    param
    (
        [Parameter(Mandatory=$true)] [string]
        $Command
    )
    
    cmd /c "$Command > nul 2>&1 && set" | .{process{
        if ($_ -match '^([^=]+)=(.*)') {
            [System.Environment]::SetEnvironmentVariable($matches[1], $matches[2])
        }
    }}
    
    if ($LASTEXITCODE) {
        throw "Command '$Command': exit code: $LASTEXITCODE"
    }
    

    附:以下是向 PowerShell 添加类似功能的建议:Extend dot sourcing concept to cmd files

    【讨论】:

    • 您可能只想使用$Command &gt; nul 2&gt;&amp;1 &amp;&amp; set,以防$Command具有非零退出代码但仍会更改环境。
    • 链接的“改进和更好测试”版本对我不起作用,但从这个答案复制粘贴脚本可以。
    • 感谢您的报警。你能创建一个问题there 并描述你的用例吗?
    • 我在那里没有帐户。我试过: Invoke-Environment '"%VS120COMNTOOLS%\vsvars32.bat"' -Force
    • 已修复(奇怪,cmd 在 /c 之后需要一个额外的空格)。我现在无法尝试使用 VS120COMNTOOLS,但使用 VS100COMNTOOLS 可以正常工作。
    【解决方案3】:

    是否可以将您的批处理脚本转换为 PowerShell 脚本?如果您运行 bat 文件,它会在不修改 PowerShell 环境变量的单独会话中执行。

    您可以非常顺利地使用环境变量:

    PS> Get-ChildItem env:
    
    Name                           Value
    ----                           -----
    ALLUSERSPROFILE                C:\ProgramData
    APPDATA                        C:\Users\xyz\AppData\Roaming
    CommonProgramFiles             C:\Program Files (x86)\Common Files
    CommonProgramFiles(x86)        C:\Program Files (x86)\Common Files
    CommonProgramW6432             C:\Program Files\Common Files
    COMPUTERNAME                   xyz
    ComSpec                        C:\Windows\system32\cmd.exe
    DXSDK_DIR                      D:\prgs\dev\Microsoft DirectX SDK (August 2009)\
    FP_NO_HOST_CHECK               NO
    HOMEDRIVE                      Z:
    HOMEPATH                       \
    ...
    
    PS> Get-Item env:path
    Name  Value
    ----  -----
    Path  c:\dev\CollabNet\SubversionClient;C:\Windows\system32;...
    

    甚至(更短,只返回字符串):

    PS> $env:path
    c:\dev\CollabNet\Subversion Client;C:\Windows\system32;...
    

    你可以像这样改变环境路径:

    PS> $env:path += ";c:\mydir"
    

    您甚至可以像这样在机器级别设置环境变量:

    # fist arg = env variable name, second = value, third = level, available are 'Process', 'User', 'Machine'
    PS> [Environment]::SetEnvironmentVariable('test', 'value', 'machine')
    

    【讨论】:

      【解决方案4】:

      @Roman Kuzmin 的解决方案效果很好,但是将命令输出通过管道传输到 nul 可能会让您一头雾水。因此,我进行了一些调整以使命令输出正常显示,而是将环境变量通过管道传输到临时文件以供之后读取:

      param
      (
          [Parameter(Mandatory=$true)] [string]
          $Command
      )
      $VarsPath = [IO.Path]::GetTempFileName()
      cmd /c "$Command && set > $VarsPath"
      if (-not $LASTEXITCODE) {
          Get-Content $VarsPath | ForEach-Object {
              if ($_ -match '^([^=]+)=(.*)') {
                  [System.Environment]::SetEnvironmentVariable($matches[1], $matches[2])
              }
          }
      }
      Remove-Item $VarsPath
      

      【讨论】:

        【解决方案5】:

        您可以通过输入名称从 Powershell 运行批处理脚本,但这对您没有帮助。批处理脚本中设置的环境变量仅在该批处理和该批处理运行的任何内容中可见。一旦控件返回到 Powershell,环境变量就消失了。不过,您可以让批处理脚本在最后运行 set,然后将其输出解析到您的 PSH 环境变量中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-10-14
          • 1970-01-01
          • 2013-07-30
          • 1970-01-01
          • 1970-01-01
          • 2018-04-13
          • 2013-10-20
          相关资源
          最近更新 更多