Home » Javascript » Pass Node.js environment variable with Windows PowerShell [duplicate]

Pass Node.js environment variable with Windows PowerShell [duplicate]

Posted by: admin November 23, 2021 Leave a comment

Questions:

I’m trying pass an environment variable to Node.js with PowerShell like this way:

C:\Users\everton\my-project> $env:MY_VAR = 8000 node index.js

But I get an error in PowerShell:

Token ‘node’ unexpected expression or statement

Answers:

Set environmental variable MY_VAR first and run your app like this:

C:\Users\everton\my-project> $env:MY_VAR="8000" ; node index.js

You can access environmental variable MY_VAR inside index.js by

process.env.MY_VAR

Note: PowerShell doesn’t directly support command-scoped environment variables. The above command sets the environment variable for that PowerShell session.

###

My answer require the use of Node.js and npm libraries.

…or you just take out the pain of writing obscure-WTF-language-scripting, and use one of command-scoped (plus cross-platform) Node.js scripts:

  • cross-env (for inline)

    cross-env MYVAR=MYVALUE node index.js
    
  • env-cmd (from .env file)

    env-cmd .env node index.js
    

    with

    #.env file
    MYVAR=MYVALUE
    

###

Note: If you can assume that Node.js is already installed – as is by definition the case when you’re invoking node – consider use of npm helper packages, as shown in Cyril CHAPON ‘s helpful answer.
This answer focuses on generic solutions from within PowerShell.

tl;dr

# Set env. variable temporarily, invoke the external utility, 
# then remove / restore old value.
$oldVal, $env:MYVAR = $env:MYVAR, 8000; node index.js; $env:MYVAR = $oldVal
# Scoped alternative that uses a *transient* helper variable.
& { $oldVal, $env:MY_VAR = $env:MY_VAR, 8000; node index.js; $env:MY_VAR = $oldVal }

More simply, if there’s no preexisting MY_VAR value that must be restored.

$env:MYVAR=8000; node index.js; $env:MYVAR=$null

See below for an explanation and an alternative based on a helper function.


To complement Harikrishnan’s effective answer:

PowerShell has no equivalent to the command-scoped method of passing environment variables that POSIX-like shells offer (as of PowerShell v7 – however, introducing it to PowerShell – not necessarily with the same syntax – is being discussed in GitHub issue #3316); e.g.:

 # E.g., in *Bash*: 
 # Define environment variable MY_VAR for the child process being invoked (`node`)
 # ONLY; in other words: MY_VAR is scoped to the command being invoked
 # (subsequent commands do not see it).
 MY_VAR=8000 node index.js

In PowerShell, as Harikrishnan’s answer demonstrates, you have to define the environment variable first, and then, in a separate statement, call the external program, so $env:MY_VAR="8000"; node index.js is the right PowerShell solution, but it is worth nothing that $env:MY_VAR stays in scope for the remainder of the session (it is set at the process level).

Note that even using a script block invoked with & to create a child scope doesn’t help here, because such child scopes only apply to PowerShell variables, not environment variables.

You can, of course, remove the environment variable manually after the node call:
Remove-Item env:MY_VAR or even just $env:MY_VAR = $null, which is what the 1st command at the top shows.


A more structured alternative – perhaps better in the case of setting multiple environment variables and/or invoking multiple commands – is to use a script block invoked with &:

& { $oldVal, $env:MY_VAR = $env:MY_VAR, 8000; node index.js; $env:MY_VAR = $oldVal }

This takes advantage of:

  • { ... } is a script block that provides a clearly visible grouping for the commands in it; invoked with &, it creates a local scope, so that helper variable $oldVal automatically goes out of scope on exiting the block.

  • $oldVal, $env:MY_VAR = $env:MY_VAR, 8000 saves the old value (if any) of $env:MY_VAR in $oldVal while changing the value to 8000; this technique of assigning to multiple variables at once (known as destructuring assignment in some languages) is explained in Get-Help about_Assignment_Operators, section "ASSIGNING MULTIPLE VARIALBES".

Alternatively, use the helper function below, or use a try { ... } finally { ... } approach, as demonstrated in this related answer.


Helper function for command-scoped environment modifications.

If you define the helper function below (remember that function definitions must be placed before they’re invoked), you can achieve command-scoped modification of your environment as follows:

# Invoke `node index.js` with a *temporarily* set MY_VAR environment variable.
Invoke-WithEnvironment @{ MY_VAR = 8000 } { node index.js }

Invoke-WithEnvironment() source code:

function Invoke-WithEnvironment {
<#
.SYNOPSIS
Invokes commands with a temporarily modified environment.

.DESCRIPTION
Modifies environment variables temporarily based on a hashtable of values,
invokes the specified script block, then restores the previous environment.

.PARAMETER Environment
A hashtable that defines the temporary environment-variable values.
Assign $null to (temporarily) remove an environment variable that is
currently set.

.PARAMETER ScriptBlock
The command(s) to execute with the temporarily modified environment.

.EXAMPLE
> Invoke-WithEnvironment @{ PORT=8080 } { node index.js }

Runs node with environment variable PORT temporarily set to 8080, with its
previous value, if any 
#>
  param(
    [Parameter(Mandatory)] [System.Collections.IDictionary] $Environment,
    [Parameter(Mandatory)] [scriptblock] $ScriptBlock
  )
  # Modify the environment based on the hashtable and save the original 
  # one for later restoration.
  $htOrgEnv = @{}
  foreach ($kv in $Environment.GetEnumerator()) {
    $htOrgEnv[$kv.Key] = (Get-Item -EA SilentlyContinue "env:$($kv.Key)").Value
    Set-Item "env:$($kv.Key)" $kv.Value
  }
  # Invoke the script block
  try {
    & $ScriptBlock
  } finally {
    # Restore the original environment.
    foreach ($kv in $Environment.GetEnumerator()) {
      # Note: setting an environment var. to $null or '' *removes* it.
      Set-Item "env:$($kv.Key)" $htOrgEnv[$kv.Key]
    }
  }
}