23

I'm replacing parts of a .bat script with PowerShell. Configuration for the batch files is done via files that set appropriate environment variables. I'm looking for a way to load those variable values into the .ps1 script, without modifying the .bat files (as they are also used in other places.

An example .bat looks as follows:

set VAR_ONE=some_value
set VAR_TWO=/other-value

In a batch script, I'd just CALL the configuration file and the variables would be available. I've tried both dot-sourcing (. filename.bat) and calling (& filename.bat) the configuration files from PowerShell, neither of those makes the variables visible. Tried accessing them with both with $VAR_ONE and $env:VAR_ONE syntax.

What would be a good way to load such configuration file without modifying it's format on disk?

skolima
  • 31,963
  • 27
  • 115
  • 151

5 Answers5

22

If you are using the PowerShell Community Extensions, it has a Invoke-BatchFile that does this. I use with the Visual Studio vcvarsall.bat file to configure my PowerShell session to use the Visual Studio tools.

Ed Elliott
  • 6,666
  • 17
  • 32
Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • This is really the better answer as it allows for sourcing variables from any batch file, even one that has logic or calls into other files. – Elliott Beach Jun 15 '19 at 17:50
8

I'd parse them (just skip all lines that don't start with set and split them with first = character. You can do it from o small C# cmdlet or directly with a small PowerShell script:

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

I have this code and I'm sure it comes from somewhere but credits have been lost, I suppose it comes from Power Shell Community Extensions for an Invoke-Batch script.

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
7

The preferred option would be to change the configuration to a .ps1 file and change the variable definitions to PowerShell syntax:

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

Then you'll be able to dot-source the file:

. filename.ps1

If you want to stick with the format you currently have, you'll have to parse the values, e.g. like this:

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

Note: The above won't work in PowerShell versions prior to v3. A v2-compatible version would look like this:

Select-String '^set ([^=]*)=(.*)' .\filename.bat | ForEach-Object {
    $_.Matches
} | ForEach-Object {
    Set-Variable $_.Groups[1].Value $_.Groups[2].Value
}
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
3

You can do that via a Batch file that first call the configuration file and then execute the PowerShell script.

Aacini
  • 65,180
  • 12
  • 72
  • 108
1

Assuming the .bat is called test.bat, define 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

Then the result is something like:

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

There is probably a nicer way of doing the splits (will edit if I find it)

Iain Ballard
  • 4,433
  • 34
  • 39