如何从Powershell调用批处理脚本?

时间:2010-12-08 06:38:30

标签: powershell batch-file

我有一个大批量脚本,它设置了一堆环境变量。 我想从powershell调用那个批处理脚本,这样我就可以获得我的脚本和powershell设置的环境变量的好处。

5 个答案:

答案 0 :(得分:21)

如果你抓住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 :(得分:12)

这个想法来自这篇博文: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"
}

P.S。以下是向PowerShell添加类似功能的提议:Extend dot sourcing concept to cmd files

答案 2 :(得分:2)

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

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

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')

答案 3 :(得分:0)

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

答案 4 :(得分:0)

@Roman Kuzmin的解决方案效果很好,但是将命令输出传递给nul可能会让您陷入困境。因此,我进行了一些调整以使命令输出正常显示,然后将env vars传递到临时文件中以供随后读取:

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