【发布时间】:2011-05-22 01:15:59
【问题描述】:
我有一个设置大量环境变量的大批量脚本。 我想从 powershell 调用该批处理脚本,这样我可以同时受益,即我的脚本和 powershell 设置的环境变量。
【问题讨论】:
标签: powershell batch-file
我有一个设置大量环境变量的大批量脚本。 我想从 powershell 调用该批处理脚本,这样我可以同时受益,即我的脚本和 powershell 设置的环境变量。
【问题讨论】:
标签: powershell batch-file
如果你抓住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.
【讨论】:
这个想法来自这篇博文: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 > nul 2>&1 && set,以防$Command具有非零退出代码但仍会更改环境。
是否可以将您的批处理脚本转换为 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')
【讨论】:
@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
【讨论】:
您可以通过输入名称从 Powershell 运行批处理脚本,但这对您没有帮助。批处理脚本中设置的环境变量仅在该批处理和该批处理运行的任何内容中可见。一旦控件返回到 Powershell,环境变量就消失了。不过,您可以让批处理脚本在最后运行 set,然后将其输出解析到您的 PSH 环境变量中。
【讨论】: