I have a .env
file like this one:
TESTCASE_GROUP_SIZE=25
. . .
And I want to get its value (read it) into a .ps1
script.
How can I do it?
I have a .env
file like this one:
TESTCASE_GROUP_SIZE=25
. . .
And I want to get its value (read it) into a .ps1
script.
How can I do it?
get-content test.env | foreach {
$name, $value = $_.split('=')
set-content env:\$name $value
}
assuming you mean "set one environment variable per line in the file".
$env:TESTCASE_GROUP_SIZE
, but environment variables are really so you can launch a program and it inherits them as its environment. If that's not what you're doing then they may be better in a hashtable rather than as individual variables. –
Germaun foreach
in if ($_) { }
to filter empty lines. Heck, you might as well filter the comments in the env file using patterns. –
Pedaias split()
so it doesn't toss them out: $_.split('=',2)
–
Asteria set-content env:$name $value
–
Grew new-Variable -Name $name -Value $value
if you want a local variable instead of an environment variable –
Rainbolt Polished version of @TessellatingHeckler's for future reference.
Get-Content .env | foreach {
$name, $value = $_.split('=')
if ([string]::IsNullOrWhiteSpace($name) || $name.Contains('#')) {
continue
}
Set-Content env:\$name $value
}
Throwing my hat into the ring. Powershell's ConvertFrom-StringData
will ignore comments and handle edge cases like multiple =
signs.
Run notepad $PROFILE
and copy it in to make it available any time you open the terminal.
<#
.SYNOPSIS
Imports variables from an ENV file
.EXAMPLE
# Basic usage
dotenv
.EXAMPLE
# Provide a path
dotenv path/to/env
.EXAMPLE
# See what the command will do before it runs
dotenv -whatif
.EXAMPLE
# Create regular vars instead of env vars
dotenv -type regular
#>
function Import-Env {
[CmdletBinding(SupportsShouldProcess)]
[Alias('dotenv')]
param(
[ValidateNotNullOrEmpty()]
[String] $Path = '.env',
# Determines whether variables are environment variables or normal
[ValidateSet('Environment', 'Regular')]
[String] $Type = 'Environment'
)
$Env = Get-Content -raw $Path | ConvertFrom-StringData
$Env.GetEnumerator() | Foreach-Object {
$Name, $Value = $_.Name, $_.Value
if ($PSCmdlet.ShouldProcess($Name, "Importing $Type Variable")) {
switch ($Type) {
'Environment' { Set-Content -Path "env:\$Name" -Value $Value }
'Regular' { Set-Variable -Name $Name -Value $Value -Scope Script }
}
}
}
}
Version 2 with Bash quoting rules by request of @YvesMartin
function Import-Env {
[CmdletBinding(SupportsShouldProcess)]
[Alias('dotenv')]
param(
[ValidateNotNullOrEmpty()]
[String] $Path = '.env',
# Determines whether variables are environment variables or normal
[ValidateSet('Environment', 'Regular')]
[String] $Type = 'Environment'
)
$Env = Get-Content -raw $Path | ConvertFrom-StringData
$Env.GetEnumerator() | Foreach-Object {
$Name, $Value = $_.Name, $_.Value
# Account for quote rules in Bash
$StartQuote = [Regex]::Match($Value, "^('|`")")
$EndQuote = [Regex]::Match($Value, "('|`")$")
if ($StartQuote.Success -and -not $EndQuote.Success) {
throw [System.IO.InvalidDataException] "Missing terminating quote $($StartQuote.Value) in '$Name': $Value"
} elseif (-not $StartQuote.Success -and $EndQuote.Success) {
throw [System.IO.InvalidDataException] "Missing starting quote $($EndQuote.Value) in '$Name': $Value"
} elseif ($StartQuote.Value -ne $EndQuote.Value) {
throw [System.IO.InvalidDataException] "Mismatched quotes in '$Name': $Value"
} elseif ($StartQuote.Success -and $EndQuote.Success) {
$Value = $Value -replace "^('|`")" -replace "('|`")$" # Trim quotes
}
if ($PSCmdlet.ShouldProcess($Name, "Importing $Type Variable")) {
switch ($Type) {
'Environment' { Set-Content -Path "env:\$Name" -Value $Value }
'Regular' { Set-Variable -Name $Name -Value $Value -Scope Script }
}
}
}
}
KEY="value1 value2"
produces same result as original Powershell $Env:KEY="value1 value2"
than means $Env:KEY container value1 value2
without double quotes. May you please propose a support for this? –
Schizopod $ExecutionContext.InvokeCommand.ExpandString()
on the value so the quotes are evaluated to the raw string. However, doing that carries risk because it would then eval any Powershell code in the string. In the absence of a string parser, making sure the string is valid is a bit of effort. –
Moderate I came up with this script:
get-content .env | foreach {
$index = $_.IndexOf('=');
$key = ''
$value =''
if ($index -ge 0) {
$key = $_.Substring(0, $index)
$value = $_.Substring($index + 1)
}
@{ $key = $value}
}
Made some additions to @jeiea's answer. Wrapped in a function that:
.env
file.$strict
to make the function throw an error if the Dotenv file does not exist. Overriding the previous functionality.=
.=
are ignored.$strict
is enabled then an error is thrown when invalid variable names are provided.'null'
values are set to literal $null
values.export
function Read-Dotenv {
param (
[string]$EnvFile = '.env', # Path to the .env file
[bool]$Strict = $false # Whether to throw an error if the file does not exist
)
# Check if the .env file exists
if (-not (Test-Path $EnvFile)) {
if ($Strict) {
Throw "The Dotenv file does not exist at the path: $EnvFile"
}
return
}
# Hashtable to store environment variables
$envVars = @{}
# Function to resolve variable references within values
function Resolve-Value {
param (
[string]$value, # The value to resolve
[hashtable]$envVars # Hashtable containing the environment variables
)
$prevValue = $null
while ($prevValue -ne $value) {
$prevValue = $value
# Resolve ${VAR} patterns
$value = [regex]::Replace($value, '\$\{(\w+)\}', {
param ($match)
if ($envVars.ContainsKey($match.Groups[1].Value)) {
$envVars[$match.Groups[1].Value]
} else {
$match.Value
}
})
# Resolve $VAR patterns
$value = [regex]::Replace($value, '\$(\w+)', {
param ($match)
if ($envVars.ContainsKey($match.Groups[1].Value)) {
$envVars[$match.Groups[1].Value]
} else {
$match.Value
}
})
}
return $value
}
# Read and process the .env file line by line
$content = Get-Content $EnvFile -Raw
$lines = $content -split "`n"
foreach ($line in $lines) {
$line = $line.Trim()
# Ignore empty lines and lines starting with '#'
if ($line.StartsWith('#') -or [string]::IsNullOrWhiteSpace($line)) {
continue
}
# Ignore 'export ' prefix
if ($line.StartsWith('export ')) {
$line = $line.Substring(7).Trim()
}
# Split by the first '=' only to separate name and value
$splitIndex = $line.IndexOf('=')
if ($splitIndex -eq -1) {
continue
}
$name = $line.Substring(0, $splitIndex).Trim()
$value = $line.Substring($splitIndex + 1).Trim()
# Validate the variable name
if ([string]::IsNullOrWhiteSpace($name) -or $name.Contains(' ')) {
if ($Strict) {
Throw "Invalid environment variable name: '$name' in line: '$line'"
}
continue
}
# Remove surrounding quotes from the value and handle escape characters
$interpolate = $true
if ($value.StartsWith('"') -and $value.EndsWith('"')) {
$value = $value.Substring(1, $value.Length - 2) -replace '\"', '"'
} elseif ($value.StartsWith("'") -and $value.EndsWith("'")) {
$value = $value.Substring(1, $value.Length - 2) -replace "\\'", "'"
$interpolate = $false
}
# Store the raw value in the hashtable
$envVars[$name] = $value
# Resolve and set the environment variable
$resolvedValue = if ($interpolate) { Resolve-Value -value $value -envVars $envVars } else { $value }
switch ($resolvedValue.ToLower()) {
'true' { [System.Environment]::SetEnvironmentVariable($name, $true, "Process") }
'false' { [System.Environment]::SetEnvironmentVariable($name, $false, "Process") }
'null' { [System.Environment]::SetEnvironmentVariable($name, $null, "Process") }
'' { [System.Environment]::SetEnvironmentVariable($name, $null, "Process") }
default { [System.Environment]::SetEnvironmentVariable($name, $resolvedValue, "Process") }
}
}
}
Polished and actually working version of what was said above:
Set-Variable EnvFileRelLoc -Option Constant -Value "../../../docker/.env";
Get-Content $EnvFileRelLoc | foreach {
$name, $value = [regex]::split($_, '(?<= |\w+)=(?= |\W+)') ;
if ([string]::IsNullOrWhiteSpace($name) -OR $name.Contains('#') -OR $name.Contains('=')) {
# do nothing
} else {
Write-host "NAME: $name ; VALUE $value";
Set-Content env:$name $value
}
}
To make this easy to access:
notepad $PROFILE
).function LoadEnvFile {
Get-Content .env | foreach {
$name, $value = $_.split('=')
if ([string]::IsNullOrWhiteSpace($name) || $name.Contains('#')) {
continue
}
Set-Content env:\$name $value
}
}
ReadEnvFile
anywhere to load an .env file in the same directory.Feel free to swap the contents of the function with anyone else's answer if you like it more.
© 2022 - 2024 — McMap. All rights reserved.