PowerShell: Setting an environment variable for a single command only

81,428

Solution 1

Generally, it would be better to pass info to the script via a parameter rather than a global (environment) variable. But if that is what you need to do you can do it this way:

$env:FOO = 'BAR'; ./myscript

The environment variable $env:FOO can be deleted later like so:

Remove-Item Env:\FOO

Solution 2

I got motivated enough about this problem that I went ahead and wrote a script for it: with-env.ps1

Usage:

with-env.ps1 FOO=foo BAR=bar your command here

# Supports dot-env files as well
with-env.ps1 .\.env OTHER_ENV=env command here

On the other hand, if you install Gow you can use env.exe which might be a little more robust than the quick script I wrote above.

Usage:

env.exe FOO=foo BAR=bar your command here

# To use it with dot-env files
env.exe $(cat .env | grep.exe -v '^#') SOME_OTHER_ENV=val your command

Solution 3

2 easy ways to do it in a single line:

$env:FOO='BAR'; .\myscript; $env:FOO=''
$env:FOO='BAR'; .\myscript; Remove-Item Env:\FOO

Just summarized information from other answers (thank you folks) which don't contain pure one-liners for some reason.

Solution 4

To accomplish the equivalent of the Unix syntax, you not only have to set the environment variable, but you have to reset it to its former value after executing the command. I've accomplished this for common commands I use by adding functions similar to the following to my PowerShell profile.

function cmd_special()
{
  $orig_master = $env:app_master
  $env:app_master = 'http://host.example.com'
  mycmd $args
  $env:app_master = $orig_master
}

So mycmd is some executable that operates differently depending on the value of the environment variable app_master. By defining cmd_special, I can now execute cmd_special from the command line (including other parameters) with the app_master environment variable set... and it gets reset (or even unset) after execution of the command.

Presumably, you could also do this ad-hoc for a single invocation.

& { $orig_master = $env:appmaster; $env:app_master = 'http://host.example.com'; mycmd $args; $env:app_master = $orig_master }

It really should be easier than this, but apparently this isn't a use-case that's readily supported by PowerShell. Maybe a future version (or third-party function) will facilitate this use-case. It would be nice if PowerShell had a cmdlet that would do this, e.g.:

with-env app_master='http://host.example.com' mycmd

Perhaps a PowerShell guru can suggest how one might write such a cmdlet.

Solution 5

Making a 'subshell' by invoking powershell with a script block allows you to scope the changes to the environment:

pwsh -Command { $env:MYVAR="myvalue"; .\path\to.exe }
Share:
81,428

Related videos on Youtube

jordivador
Author by

jordivador

Updated on October 29, 2021

Comments

  • jordivador
    jordivador over 2 years

    On Linux, I can do:

    $ FOO=BAR ./myscript
    

    to call "myscript" with the environment variable FOO being set.

    Is something similar possible in PowerShell, i.e. without having to first set the variable, call the command, and then unset the variable again?

    To be more clear about my use case - I don't want to use this as part of a script. Rather, I have a third-party script whose behavior I can control using environment variables, but, in this case, not command line arguments. So being able to alternate between typing

    $ OPTION=1 ./myscript
    

    and

    $ ./myscript
    

    would just be very handy.

    • EBGreen
      EBGreen over 14 years
      I guess my question would be why you would need to do this? I would think that there is a better solution.
    • Mark Reed
      Mark Reed almost 9 years
      That's not usually a helpful question, @EBGreen. The fact that the capability is there in UNIX shells suggests that there is a use for it. Off the top of my head: controlling the username and email address git uses for commits. There is no command-line option for those - you have to set them either in ~/.gitconfig, .git/config in each repository, or envars. Of those options, envars are clearly easier to set on-the-fly (and conveniently override the values in the files). So if I want to change my author name for one "git commit" in powershell, how to do it?
    • Kim
      Kim over 5 years
      Completely agree that asking why this is needed is pointless. It is as common as borscht when executing at the command line on Linux and those of us forced now to suffer with powershell (a syntactic nightmare if ever one existed) constantly have to search for answers to obvious techniques. Most of the time, they don;t even exist in powershell unless you count writing long scripts to do trivial things. Count me deeply frustrated with that shell ...
    • Franklin Yu
      Franklin Yu over 5 years
    • mklement0
      mklement0 over 4 years
      Thanks for the link, @FranklinYu, but at this point it would be a hopefully in a not-too-distant future version after v7.0.
  • Rich
    Rich over 14 years
    Just a thought: Couldn't you just spawn a new PowerShell process, handing the scriptblock into it via the -Command parameter? That way you don't have to clean up the environment afterwards, since that will be contained in the child process. Although I am talking to a PowerShell MVP so this probably doesn't work :-)
  • x0n
    x0n over 14 years
    Keith, we have a push-environmentblock and pop-environmentblock in Pscx for exactly this scenario ;-)
  • Keith Hill
    Keith Hill over 14 years
    Johannes, that would work as well but somehow seems like cheating. :-) The PSCX Push/Pop-EnvironmentBlock (the one I changed to make work this way) would work but it doesn't have the automatic cleanup support that a scriptblock has.
  • chwarr
    chwarr almost 8 years
    Hmmm... Don't think this answer applies here. PowerShell variables aren't environment variables. Based on the question, the asker isn't using environment variables as scratch space (like one would in CMD [if that were the case, this answer would apply]), but needs to manipulate the environment before invoking an external command and then restore the environment afterward (or something to that effect).
  • chwarr
    chwarr almost 8 years
    Don't you need to set env:foo back to its old value (perhaps unset) instead of removing it?
  • Lucas
    Lucas almost 7 years
    as @Joey mentioned, if you want to do env vars cleanly, you could: & {$pre = $env:foo; $env:foo = 'bar'; ./myscript; if ($pre) {$env:foo = $pre} else {Remove-Item env:\foo}... some might say unwieldy, but will avoid side effects...
  • ThorSummoner
    ThorSummoner over 3 years
    I assume windows has the behavior where argv arguments are cleartext in the process table for all users, contrast with environment variables that are only readable by the process owner (e.g. why passwords/secrets as configuration/environs are preferred to arguments). Is that correct?
  • pishpish
    pishpish about 3 years
    Does not work - the variable is not removed.
  • Igor
    Igor almost 3 years
    Is it possible to do something similar with interactive commands, that require user's input?
  • realtebo
    realtebo over 2 years
    The 2nd vay works for me, windows 11
  • Franck Hourdin
    Franck Hourdin about 2 years
    That's what I am looking for, ty !
  • Dois
    Dois about 2 years
    use $env:FOO=$null instead of $env:FOO=''