如何将 .bat 文件中的变量获取到 PowerShell 脚本中?

问题描述 投票:0回答:6

我正在用 PowerShell 替换 .bat 脚本的部分内容。批处理文件的配置是通过

set
适当的环境变量的文件完成的。我正在寻找一种将这些变量值加载到
.ps1
脚本中的方法,而不修改
.bat
文件(因为它们也在其他地方使用。

示例

.bat
如下所示:

set VAR_ONE=some_value
set VAR_TWO=/other-value

在批处理脚本中,我只需

CALL
配置文件和变量就可用。我已经尝试过点采购 (
. filename.bat
) 和从 PowerShell 调用 (
& filename.bat
) 配置文件,这两种方法都没有使变量可见。尝试使用
$VAR_ONE
$env:VAR_ONE
语法访问它们。

在不修改磁盘格式的情况下加载此类配置文件的好方法是什么?

windows powershell batch-file cmd environment-variables
6个回答
22
投票

如果您使用的是 PowerShell 社区扩展,它有一个

Invoke-BatchFile
可以执行此操作。我使用 Visual Studio vcvarsall.bat 文件来配置我的 PowerShell 会话以使用 Visual Studio 工具。


8
投票

我会解析它们(只需跳过所有不以

set
开头的行,并用第一个
=
字符将它们分开。您可以通过小型 C# cmdlet 或直接使用小型 PowerShell 脚本来完成此操作:

CMD /c "batchFile.bat && set" | .{process{
    if ($_ -match '^([^=]+)=(.*)') {
        Set-Variable $matches[1] $matches[2]
    }
}}

我有这段代码,我确定它来自某个地方,但积分已丢失,我想它来自 Invoke-Batch

 脚本的 
Power Shell 社区扩展


7
投票

首选选项是将配置更改为 
.ps1

文件并将变量定义更改为 PowerShell 语法:

$VAR_ONE = 'some_value' $VAR_TWO = '/other-value'

然后您将能够对文件进行点源:

. filename.ps1

如果您想坚持使用当前的格式,则必须解析这些值,例如像这样:

Select-String '^set ([^=]*)=(.*)' .\filename.bat | ForEach-Object { Set-Variable $_.Matches.Groups[1].Value $_.Matches.Groups[2].Value }

注意:

以上内容在 v3 之前的 PowerShell 版本中不起作用。 v2 兼容版本将如下所示:

Select-String '^set ([^=]*)=(.*)' .\filename.bat | ForEach-Object { $_.Matches } | ForEach-Object { Set-Variable $_.Groups[1].Value $_.Groups[2].Value }

3
投票

您可以通过批处理文件来完成此操作,首先
call配置文件,然后然后

执行PowerShell脚本。

1
投票

假设.bat名为
test.bat
,定义
testps.ps1


$lines = cat "test.bat" $output = @{}; foreach ($line in $lines) { $bits = $line.Split("="); $name = $bits[0].Split(" ")[1]; $val = $bits[1]; $output[$name] = $val } return $output

那么结果是这样的:

C:\temp> .\testps.ps1 Name Value ---- ----- VAR_TWO /other-value VAR_ONE some_value C:\temp> $x = .\testps.ps1 C:\temp> $x Name Value ---- ----- VAR_TWO /other-value VAR_ONE some_value C:\temp> $x["VAR_ONE"] some_value

可能有更好的分割方法(如果我找到它,将进行编辑)

0
投票
  • 从 PowerShell 调用批处理文件必然会在子进程

    中执行批处理文件,因为必须启动 
    cmd.exe

    子进程才能执行它。
  • 在子进程(批处理文件)中设置的任何环境变量都不会被调用进程(PowerShell)看到

因此,需要一个解决方法

cmd /c 'sample.cmd >NUL & SET' | 
  Where-Object { $_ -notmatch '^PROMPT=' } |
  ForEach-Object {
    # Split the "<name>=<value>" line into the variable's name and value.
    $name, $value = $_ -split '=', 2
    # Define it as a process-level environment variable in PowerShell.
    Set-Content ENV:$name $value
  }

注意

  • 基本假设是目标批处理文件

    使用
    setlocal(因为这会将变量的范围限制为该批处理文件);也就是说,批处理文件的明确目的是按设计为调用者设置环境变量,但它却不会。

  • 假设调用批处理文件的唯一目的是捕获批处理文件设置的环境变量;因此,后者的 output - 如果有的话 - 被丢弃 (

    >NUL
    ),这简化了输出的解析。

  • 执行

    SET
    (在批处理文件调用之后无条件地通过
    &
    )将所有当时的环境变量定义打印为
    <name>=<value>
    对。

    • cmd.exe
      还定义了一个
      PROMPT
      环境变量,该变量与PowerShell或其他进程无关,所以上面将其过滤掉。
  • 通过

    ForEach-Object
    调用,
    $name, $value = $_ -split '=', 2
    然后将每个
    <name>=<value>
    对分成其组成部分。

  • 上面的假设批处理文件环境变量也应该在PowerShell中定义为环境变量,使用

    Env:
    PowerShell驱动器
    Set-Content

    • 相比之下,如果使用
      Set-Variable
      ,则将创建仅限 PowerShell 变量,这些变量只能由当前 PowerShell 会话看到,而不能由从中调用的 子进程看到。
  • 上述解决方案没有考虑批处理文件可能执行的环境变量的删除;还需要做更多的工作来传播清除情况。

© www.soinside.com 2019 - 2024. All rights reserved.