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

26

我有一个设置多个环境变量的批处理脚本。我想从PowerShell中调用该批处理脚本,这样我就可以同时享受两者的好处,即我的脚本设置的环境变量和PowerShell。

5个回答

26
如果您下载PowerShell社区扩展,其中有一个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目录下放置文件夹。 http://stam.blogs.com/8bits/2010/06/installing-powershell-community-extensions.html - AnneTheAgile

13

这个想法来自于这篇博客文章:“没有一种方法可以解决所有问题” - PowerShell和其他技术

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


更新:此脚本的改进并且经过了更好的测试,可以在这里找到: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中:将点运算符概念扩展到cmd文件


1
为了防止$Command具有非零退出代码但仍更改环境,您可能希望仅使用$Command > nul 2>&1 && set - Joey
链接的“改进和更好测试”的版本对我不起作用,但从这个答案中复制脚本却可以。 - Scott Langham
谢谢您设置提醒。您能在这里创建一个问题并描述您的用例吗? - Roman Kuzmin
修正(怪异,cmd需要在/c后再加一个空格)。我现在无法尝试使用VS120COMNTOOLS,但是在使用VS100COMNTOOLS时它可以很好地工作。 - Roman Kuzmin
所以...如果批处理文件调用/运行其他批处理文件,或者如果它分支并且仅根据某些条件设置特定的环境变量,则这不是一个完整的解决方案,可能会错过或不适当地设置值?我并不是在抱怨,只是想验证我对它正在做什么的理解。 - Code Jockey
显示剩余4条评论

2

您是否可以将批处理脚本转换为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')

1

@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

0

你可以通过在PowerShell中输入批处理文件的名称来运行它,但这并没有什么帮助。在批处理脚本中设置的环境变量只能从该批处理和该批处理运行的任何内容中可见。一旦控制返回到PowerShell,环境变量就会消失。不过,你可以让批处理脚本在结尾处运行set命令,然后将其输出解析为PSH环境变量。


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