1

In a Powershell script (.ps1) Launched from the command line of a console (cmd.exe)

How can set and environment variable in the console,
so that when the Powershell script ends processing,
and exits to the console where was invoked...
the environment variable exists,
and can be read by a batch file,
or viewed with the SET command ?

do not want to set a 'Machine' or a 'User' variable...
only a console process variable...
the same variable you get if you use SET in the console

1 Answer 1

3

To run a PowerShell script from cmd.exe invariably requires a (powershell.exe / pwsh.exe) child process, and child processes fundamentally cannot set environment variables for their parent process[1].

Your best bet is to have your *.ps1 file output the name and value of the desired environment variable and then have the calling cmd.exe process create it, based on that output.

Security note: Blindly defining environment variables based on the name-value pairs output by another command (a *.ps1 script, in your case) should only be done if you trust that command not to output malicious definitions.

Here's a simple example (run directly from an interactive cmd.exe session):

for /f "delims== tokens=1,*" %v in ('powershell.exe -c "'FOO=bar'"') do @set "%v=%w"

The above defines environment variable %FOO% with value bar, based on the PowerShell command outputting the literal name-value pair FOO=bar. Verify with echo %FOO%.

To extend this approach to defining multiple environment variables, make the command output each definition on its own line (which in PowerShell you can achieve by outputting an array of strings):

for /f "delims== tokens=1,*" %v in ('powershell.exe -c "'FOO=bar', 'BAZ=bam'"') do @set "%v=%w"

The above additionally defines %BAZ% with value bam.


To make this more convenient, I suggest creating a wrapper batch file (*.cmd) that performs the above:

  • Note that you'll have to use %%v and %%w instead of %v and %w there.

  • Instead of -c (for -Command) with the demo command, use -File with the path to your *.ps1 file to invoke it.

    • Also consider use of -NoProfile as well, to bypass loading of your PowerShell environment's $PROFILE file, which not only slows things down, but may pollute your command's output.

[1] As LotPings points out, child processes inherit copies of the parent process' environment variables. Modifications of these copies are never seen by the parent. A child process is fundamentally unable to modify its parent's environment, which is a restriction at the OS level - for good reasons: Modifying a running process' environment by an arbitrary (child) process would be a serious security concern.

3
  • 2
    @ZEE: LotPings is correct: this restriction is an OS-level restriction (not just on Windows), and it exists for good reasons - see the footnote I've added to the answer. I've also amended the solution to output not just the value but also the name of the environment variable(s) to define.
    – mklement0
    Commented Jun 9, 2019 at 15:57
  • Understable... but as this is a MS thing... and the CMD/BATCH console is yet ubiquitous... and there are lots os Powershell scripts invoked fom the CMD.exe command line... I wish they had tought about this... and come out with a solution... ;-)
    – ZEE
    Commented Jun 11, 2019 at 7:37
  • @ZEE: If you need a simple solution, stick with a given shell: with cmd.exe, use a batch file to set the environment variables; with PowerShell, use a *.ps1 file; in both cases, the batch file / script runs in-process. Calling PowerShell from cmd.exe generally works, just not in your specific scenario, by design, as explained. Under the circumstance, the solution in this answer (or a variation thereof) is your best bet.
    – mklement0
    Commented Jun 11, 2019 at 10:26

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.