15

I want to extend the current PATH variable with a C# program. Here I have several problems:

  1. Using GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine) replaces the placeholders (i.e. '%SystemRoot%\system32' is replaced by the current path 'C:\Windows\system32'). Updating the PATH variable, I dont want to replace the placeholder with the path.

  2. After SetEnvironmentVariable no program can't be opened from the command box anymore (i.e. calc.exe in the command box doesn't work). Im using following code:

String oldPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
Environment.SetEnvironmentVariable("PATH", oldPath + ";%MYDIR%", EnvironmentVariableTarget.Machine);

After editing and changing the PATH variable with Windows everything works again. (I thing changes are required, otherwise it is not overwritten)

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Freddy
  • 693
  • 2
  • 6
  • 12
  • Why not use a placeholder for the PATH? `SetEnvironmentVariable("PATH", "%PATH%;%MYDIR%", EnvironmentVariableTarget.Machine);` – Mark H Aug 19 '11 at 13:04
  • 1
    Then the PATH Variable is: '%PATH%;%MYDIR%' – Freddy Aug 19 '11 at 13:25
  • 1
    Ah, sorry then. I thought that may work as it does from the command line with `SET PATH=%PATH%`. I'm not sure what to suggest then, other than a string replace with the placeholders. – Mark H Aug 19 '11 at 13:29
  • Using the command line like `SET PATH=%PATH%;%MYDIR%` doesn't work for me either ... – Freddy Aug 19 '11 at 13:40

6 Answers6

5

You can use the registry to read and update:

string keyName = @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment";
//get non-expanded PATH environment variable            
string oldPath = (string)Registry.LocalMachine.CreateSubKey(keyName).GetValue("Path", "", RegistryValueOptions.DoNotExpandEnvironmentNames);

//set the path as an an expandable string
Registry.LocalMachine.CreateSubKey(keyName).SetValue("Path", oldPath + ";%MYDIR%",    RegistryValueKind.ExpandString);
1

You can use WMI to retrieve the raw values (not sure about updating them though):

ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_Environment WHERE Name = 'PATH'");
foreach (ManagementBaseObject managementBaseObject in searcher.Get())
     Console.WriteLine(managementBaseObject["VariableValue"]);

Check WMI Reference on MSDN

Strillo
  • 2,952
  • 13
  • 15
1

You could try this mix. It gets the Path variables from the registry, and adds the "NewPathEntry" to Path, if not already there.

static void Main(string[] args)
    {
        string NewPathEntry = @"%temp%\data";
        string NewPath = "";
        bool MustUpdate = true;
        string RegKeyName = @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment";
        string path = (string)Microsoft.Win32.Registry.LocalMachine.OpenSubKey(RegKeyName).GetValue
            ("Path", "", Microsoft.Win32.RegistryValueOptions.DoNotExpandEnvironmentNames);
        string[] paths = path.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
        foreach (string subPath in paths)
        {
            NewPath += subPath + ";";
            if (subPath.ToLower() == NewPathEntry.ToLower())
            {
                MustUpdate = false;
            }
        }
        if (MustUpdate == true)
        {
            Environment.SetEnvironmentVariable("Path", NewPath + NewPathEntry, EnvironmentVariableTarget.Machine);
        }
    }
Daro
  • 1,990
  • 2
  • 16
  • 22
0

Using Registry.GetValue will expand the placeholders, so I recommend using Registry.LocalMachine.OpenSubKey, then get the value from the sub key with options set to not expand environment variables. Once you've manipulated the path to your liking, use the registry to set the value again. This will prevent Windows "forgetting" your path as you mentioned in the second part of your question.

const string pathKeyName = @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment";
var pathKey = Registry.LocalMachine.OpenSubKey(pathKeyName);
var path = (string)pathKey.GetValue("PATH", "", RegistryValueOptions.DoNotExpandEnvironmentNames);
// Manipulate path here, storing in path
Registry.SetValue(String.Concat(@"HKEY_LOCAL_MACHINE\", pathKeyName), "PATH", path);
Isaac Overacker
  • 1,385
  • 10
  • 22
0

You could go through the registry...

string keyName = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment";
//get raw PATH environment variable
string path = (string)Registry.GetValue(keyName, "Path", "");

//... Make some changes

//update raw PATH environment variable
Registry.SetValue(keyName, "Path", path);
0

While working on the application we had to have an option to use Oracle instantclient from user-defined folder. In order to use the instantclient we had to modify the environment path variable and add this folder before calling any Oracle related functionality. Here is method that we use for that:

    /// <summary>
    /// Adds an environment path segments (the PATH varialbe).
    /// </summary>
    /// <param name="pathSegment">The path segment.</param>
    public static void AddPathSegments(string pathSegment)
    {
        LogHelper.Log(LogType.Dbg, "EnvironmentHelper.AddPathSegments", "Adding path segment: {0}", pathSegment);
        string allPaths = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process);
        if (allPaths != null)
            allPaths = pathSegment + "; " + allPaths;
        else
            allPaths = pathSegment;
        Environment.SetEnvironmentVariable("PATH", allPaths, EnvironmentVariableTarget.Process);
    }

Note that this has to be called before anything else, possibly as the first line in your Main file (not sure about console applications).

Dalibor Čarapić
  • 2,792
  • 23
  • 38