views:

574

answers:

4

Is it possible to persist an environment variable in a console application which is available after the process has exited.

I want a console application to set a string which is available to the batch file which executed it.

The console application is in dotnet.

+3  A: 

You can use Environment.SetEnvironmentVariable:

Environment.SetEnvironmentVariable("SomeVariable", "Some value", EnvironmentVariableTarget.User);

The last parameter will determine the scope and lifetime of the variable (either Process, User or Machine). If you want to set the variable for the machine you will need to run as admin.

Edit: I do notice though that if executing a console application with the above code, the environment variable is not available until you open a new command window (so if executing the console app from a batch file, the variable will not be available to the batch file, unless there is a trick to have it refresh the set of environment variables that it sees).

Edit 2: OK, I was digging around with this and there seem to be no obvious way to have the batch file get a refreshed set of environment variables. One workaround that I found is to to have the .net code write a batch file for setting the variables, instead of setting them itself. The calling batch script can then run the created batch file to have the environment set up:

.Net Console App:

static void Main(string[] args)
{
    string outputFile = @"c:\temp\setvars.bat";
    string variable = "set SomeVariable=Some value";
    File.WriteAllText(outputFile, variable);
}

BAT-file:

call myconsoleapp.exe
call c:\temp\setvars.bat
echo %SomeVariable%
Fredrik Mörk
You beat me to it. I think this is quite a good solution, and I had a slightly different take on it in my answer. I don't think there's any other 'nice' way of doing it.
Xiaofu
This solution worked beautifully, pity there is this limitation on the environment variables, but a workaround will do.
benPearce
A: 

Yes, set a system environment variable instead of a process environment variable. (I think that technically, a User evironment variable will persist also, but only for that user's contexts).

Use the system.environment class to get to the SetEnvironmentVariable method.

RBarryYoung
This doesn't work beyond the scope of the process.Once it's exited, the environment variable is not available from the script that called it.However I am unsure what you were referring to by "system environment variable" the EnvironmentVariableTarget enum only has values Process, User and Machine.
Don Vince
*process* variables only persist for the scope of the process. User environment variables are stored in HKCU and get loaded when a process for that user is created. System(Machine) variables are stored in HKLM and get loaded when any shell process is created in that logical machine.
RBarryYoung
+3  A: 

Since you want a batch file to be able to read it, you're probably restricted to using traditional environment variables.

Try using Environment.SetEnvironmentVariable with an EnvironmentVariableTarget of User or Machine. You should then be able to get at it from your batch file with something like %my_var%.

Environment.SetEnvironmentVariable("my_var", "data", EnvironmentVariableTarget.User);

EDIT: Fredrik there beat me to it with a similar solution, and I agree that this is known behaviour for environment variables. I was going to propose having your C# app write the strings you want to return to a text file, and then parse it in your batch file. For example:

for /f "tokens=1,2 delims=," %%a in (data.txt) do (
if %%a==env1 echo %%b
if %%a==env2 echo %%b
)

...where data.txt might look like:

env1,hello
env2,there
Xiaofu
+1  A: 

This is similar to Xiaofu's, except that you might want to skip the text file altogether and have your program write the data to the console. Put ticks around the program name to have the batch file execute it and use the output, like this:

for /f "tokens=1,2 delims=," %%a in ('MyProgram.exe') do (
    set %%a=%%b
    set %%a=%%b
)

If you want to output other lines of text that should be ignored, then you could add a filter inside the for-loop.

Neil Whitaker