4

I am developing a C# application.

I need to create and pass variables to a new process and I am doing it using ProcessStartInfo.EnvironmentVariables.

The new process must run elevated so I am using Verb = "runas"

var startInfo =  new ProcessStartInfo(command)
{
    UseShellExecute = true,
    CreateNoWindow = true,
    Verb = "runas"
};
foreach (DictionaryEntry entry in enviromentVariables)
{
    startInfo.EnvironmentVariables.Add(entry.Key.ToString(), entry.Value.ToString());
}

The problem is that according to the msdn documentation:

You must set the UseShellExecute property to false to start the process after changing the EnvironmentVariables property. If UseShellExecute is true, an InvalidOperationException is thrown when the Start method is called.

but the runas variable requires UseShellExecute=true

Is there a way to do both: run process as elevated and also set the environment variables?

EDIT

I will try to rephrase my question...

Is there a way to pass arguments securly to another process so only the other process will be able to read the arguments.

user844541
  • 2,868
  • 5
  • 32
  • 60
  • Maybe not nice but might work: create a batchfile first and set the environment vars with setx /M key value. You first run the batch script and then real command. That will clutter your machinewide environmentvars though. – rene Aug 06 '12 at 11:50
  • Thanks, but that might cause a security hole, because everyone running under this user can read the global enviorment variables – user844541 Aug 06 '12 at 12:08
  • Yeah, I already said that it wasn't nice...and that was an understatement :-( – rene Aug 06 '12 at 12:10
  • Did you try setting the Environment vars in (by means of System.Environment.SetEnvironmentVariable(key, balue)); and then start the process? – rene Aug 06 '12 at 12:23
  • but how can I do that when UseShellExecute = true? – user844541 Aug 06 '12 at 12:30

2 Answers2

2

It works but on the downside is that it also shows a second command prompt, the enviroment vars are only set in the context of the started process so the settings are not propagating to the whole box.

    static void Main(string[] args)
    {
        var command = "cmd.exe";
        var environmentVariables = new System.Collections.Hashtable();
        environmentVariables.Add("some", "value");
        environmentVariables.Add("someother", "value");

        var filename = Path.GetTempFileName() + ".cmd";
        StreamWriter sw = new StreamWriter(filename);
        sw.WriteLine("@echo off");
        foreach (DictionaryEntry entry in environmentVariables)
        {
            sw.WriteLine("set {0}={1}", entry.Key, entry.Value);
        } 
        sw.WriteLine("start /w {0}", command);
        sw.Close();
        var psi = new ProcessStartInfo(filename) {
            UseShellExecute = true, 
            Verb="runas"
        };
        var ps =  Process.Start(psi);
        ps.WaitForExit();
        File.Delete(filename);
    }
rene
  • 41,474
  • 78
  • 114
  • 152
  • Thanks! do you know how secure this approach is? – user844541 Aug 06 '12 at 13:28
  • Very secure or very unsecure, depends on your context. Are you planning to do very unsecure things? – rene Aug 06 '12 at 13:31
  • I am passing a password to my application. I need that no one except the new process will be able to read the password. I am also checking if the exe is signed before calling it. – user844541 Aug 06 '12 at 13:44
  • 3
    Then don't use a temporary batch file, since it will be readable for the duration of the program. You could use a custom wrapper program that receives the password via a shared memory block. (And overwrites it as soon as it is received.) – Raymond Chen Aug 06 '12 at 13:46
  • And where do you plan storing the password? – rene Aug 06 '12 at 13:54
  • I plan to encrypt it with a password that I will ask from the user to enter. – user844541 Aug 07 '12 at 08:51
0

There's a better answer: you can still call Process.Start() with a ProcessStartInfo that has UseShellExecute = true, provided that the method you call it from has been labeled with the [STAThread] attribute.

Victor Rosu
  • 241
  • 2
  • 4