This question already has an answer here:
How to set system environment variable in C#?
(1 answer)
Closed 7 years ago.
I'm trying to add a value to the Path environment variable, but I can't seem to get it to work. I've went through a couple of similar questions and I'm pretty sure I have exactly the same code, but still it won't add the variable or I can't see it. I've checked both the administrator and local user account for changes. I've checked both during and after the running (debugging) of the application. I've also close VS2013 completely and checked.
Here's the code I'm using
string path = #"C:\Users\bono\Documents\Visual Studio 2013\Projects\3D-Scanner\AddEnviromentToPath\bin\Debug\AddEnviromentToPath.exe";
ProcessStartInfo process_start_info = new ProcessStartInfo();
process_start_info.FileName = path;
process_start_info.Verb = "runas";
process_start_info.WindowStyle = ProcessWindowStyle.Normal;
process_start_info.UseShellExecute = true;
process_start_info.Arguments = PATH_TO_PCL;
Process.Start(process_start_info); //Process that handles the adding of the value
AddEnviromentToPath program:
class Program {
static void Main(string[] args) {
//Just to make sure we're adding both
AddToEnvironmentPath(args[0], EnvironmentVariableTarget.User);
AddToEnvironmentPath(args[0], EnvironmentVariableTarget.Machine);
}
static void AddToEnvironmentPath(string pathComponent, EnvironmentVariableTarget target) {
string targetPath = System.Environment.GetEnvironmentVariable("Path", target) ?? string.Empty;
if (!string.IsNullOrEmpty(targetPath) && !targetPath.EndsWith(";")) {
targetPath = targetPath + ';';
}
targetPath = targetPath + pathComponent;
Environment.SetEnvironmentVariable("Path", targetPath, target);
}
}
Note that I'm running VS2013 and the main application as a standard user. When the AddEnviromentToPath program runs I get an admin verification panel. I log in here with an admin account.
Edit:
Other people seem to get it working with basically the same code:
How do I get and set Environment variables in C#?
Environment is not being set in windows using c#. Where am I going wrong?
Assuming that Environment.SetEnvironmentVariable calls the Win32 SetEnvironmentVariable function behind the scenes, this note is probably applicable:
Sets the contents of the specified environment variable for the
current process
...
This function has no effect on the system
environment variables or the environment variables of other processes.
If you want to change a global environment variable and have existing processes notice it, you need to:
Save it to the registry under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
Notify existing processes of the change with the WM_SETTINGCHANGE message.
See the MSDN Environment Variables documentation for more information.
ProcessStartInfo to the rescue!
You need to check this documentation out:
https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.environmentvariables%28v=vs.110%29.aspx
The key text which addresses your concerns:
Although you cannot set the EnvironmentVariables property, you can
modify the StringDictionary returned by the property.
Related
i am writing a c# binary cmdlet. at end it should installed on machine for immediate using when starting the ISE or PS-Console without Import-Module.
now i want to provide machine-wide some own $env:Variables like ex. $env:ProgramFiles. how i can do this?
Thanks!
EDIT:
for a more descriptive example here a code sniped:
namespace InstallTools.UpdateEnvironment
{
[Cmdlet(VerbsData.Update, "Environment")]
[OutputType(typeof(UpdateEnvironment))]
public class UpdateEnvironment : PSCmdlet
{
[Parameter(Position = 1,
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = "ENVIRONMENT")]
public SwitchParameter SetEnvironment { get; set; }
protected override void ProcessRecord()
{
if(SetEnvironment .IsPresent)
{
Environment.SetEnvironmentVariable("CDir", this.MyInvocation.PSScriptRoot);
Environment.SetEnvironmentVariable("CurrentTime", DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss"));
}
}
}
}
if i call in PS Update-Environment -SetEnvironment all the doings will executed. in my case, Environment.SetEnvironmentVariable ("test", "testval") causes an $env:test to be available at runtime.
However, I want the variables to be initialized automatically when the ISE is opened, without calling Update-Environment.
Thanks at all!!
For immediate usage of your module when starting the ISE or PS-Console typing Import-Module you can modify the PSModulePath environment variable.
According to Modifying the PSModulePath Installation Path.
The PSModulePath environment variable stores the paths to the locations of the modules that are installed on disk. PowerShell uses this variable to locate modules when the user does not specify the full path to a module. The paths in this variable are searched in the order in which they appear.
When PowerShell starts, PSModulePath is created as a system environment variable with the following default value: $HOME\Documents\PowerShell\Modules; $PSHOME\Modules on Windows and $HOME/.local/share/powershell/Modules: usr/local/share/powershell/Modules on Linux or Mac, and $HOME\Documents\WindowsPowerShell\Modules; $PSHOME\Modules for Windows PowerShell.
This article also answered the second part of your question :
To add paths to the PSModulePath environement variable, use one of the 3 following methods:
1) To add a temporary value that is available only for the current session, run the following command at the command line:
$env:PSModulePath = $env:PSModulePath + "$([System.IO.Path]::PathSeparator)$MyModulePath"
2) To add a persistent value that is available whenever a session is opened, add the above command to a PowerShell profile file ($PROFILE)>
$profile.AllUsersAllHosts
C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
For more information about profiles, see about_Profiles.
3) To add a persistent variable to the registry, create a new user environment variable called PSModulePath using the Environment Variables Editor in the System Properties dialog box.
To add a persistent variable by using a script, use the .Net method SetEnvironmentVariable on the System.Environment class. For example, the following script adds the C:\Program Files\Fabrikam\Module path to the value of the PSModulePath environment variable for the computer. To add the path to the user PSModulePath environment variable, set the target to "User".
$CurrentValue = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
[Environment]::SetEnvironmentVariable("PSModulePath", $CurrentValue + [System.IO.Path]::PathSeparator + "C:\Program Files\Fabrikam\Modules", "Machine")
I have created a script using Python2.7 and compiled it using pyinstaller into an exe of the same name, in this case "GeneralStats.py" turns into "GeneralStats.exe" using --onefile and -w arguments.
When called with C# I use:
var pythonDirectory = (Directory.GetCurrentDirectory());
var filePathExe1 = Path.Combine(pythonDirectory + "\\Python\\GeneralStats.exe");
Process.Start(filePathExe1);
When called outside of C#, so in my local files I can run the .exe and the result is a text file with lots of values in (Running correctly).
However, when ran with C# in this format, I get an error that "GeneralStats returned -1!"
Which I have had issues with before, but it was a simple python error that when I returned to my code and ran it, I would receive an error that I overlooked.
This time my python code returns no errors and works outside of C#.
Any ideas of why this could be? I can provide any code or file directories necessary, please just ask if you feel it would help with debugging.
EDIT:
Solved by removing:
var filePathExe1 = Path.Combine(pythonDirectory + "\\Python\\GeneralStats.exe");
Process.Start(filePathExe1);
And replacing with:
ProcessStartInfo _processStartInfo = new ProcessStartInfo();
_processStartInfo.WorkingDirectory = Path.Combine(pythonDirectory + "\\Python");
_processStartInfo.FileName = #"GeneralStats.exe";
_processStartInfo.CreateNoWindow = true;
Process myProcess = Process.Start(_processStartInfo);
You need to set the working directory for the Process - it is probably trying to load files from its working directory but isn't finding them.
See, e.g. this:
Use the ProcessStartInfo.WorkingDirectory property to set it prior to starting the process. If the property is not set, the default working directory is %SYSTEMROOT%\system32.
Set it to the path where GeneralStats.exe is.
The action I need help about, is to execute a EXE file on own servers disk from a intranet-webpage, which IIS are on same server-installation. The webpage use a business layer to execute a ProcessStart together with given parameters.
When I perform the execution from web, the taskmanager show me that the application are starting up with the IIS AppPool of webpage as user. Few seconds later it's killed. In my database logs, I can see;
The Microsoft Jet database engine cannot open the file '\\computer\pathfile.ext'. It is already opened exclusively by another user, or you need permission to view its data.
That's correct. The EXE tool are, in turn, loading files from other computers. This is a special behavior which are well studied and well working while using the tool from desktop.
My goal/question,
I want this web-function-call behave with desktop rights. Is it possible at all?
The IIS AppPool have a regular setup with account ApplicationPoolIdentity. I appeared to be "lucky unwise", without knowledge about how much IIS 7.5 and Windows Server 2008 R2 raised the security model since <=IIS6.
I tried to change the app-pool user to NetworkService, Administrator.
I tried to set the application with app-pool as exec/read right
I even tried to let webapp to run a batch-file with a call to application inside..
Then I was begin to change the ProcessStart-behavior. And here, I
don't know much of what to do. I tried to add VERB runas. Force a
password prompt is not a solution here. I tried to simulate a
username/password. No luck there. I also tried to add runas /user:
blabla as parameters with ProcessStart, after used /savecred in a
desktop command window once. No luck there.
Maybe this should work but I just don't understand the correct setup of properties. I add the ProcessStart code snippet below, also added some commented code to let you see what I tried.
public string RunProcess(ApplicationType type, int param)
{
currentSelection = GetApplicationType(type);
ProcessStartInfo info = new ProcessStartInfo(currentSelection.Path);
info.CreateNoWindow = false;
info.UseShellExecute = true;
//info.UseShellExecute = false;
//info.ErrorDialog = false;
//info.UserName = "dummyUsEr";
//info.Password = this.SecurePwd("DummyPWd");
info.WindowStyle = ProcessWindowStyle.Normal;
info.Arguments = string.Format(" {0}", param.ToString());
using (Process exec = Process.Start(info))
{
try
{
exec.WaitForExit();
}
catch
{
}
}
return output;
}
EDIT
Just to be clear, and perhaps help some another guy/girl browsing to this question, I attach the snippet of Password-generation,
protected System.Security.SecureString SecurePwd(string pwd)
{
SecureString securePwd = new SecureString();
foreach (char ch in pwd.ToCharArray())
securePwd.AppendChar(ch);
return securePwd;
}
I see that you've tried putting in a specific username and password for the process start impersonation, but you say that the process accesses files on another computer and I don't see any mention of specifying a domain name which presumably you would need to access remote files?
So like this:
info.Domain = "domainname";
info.UserName = "dummyUsEr";
info.Password = "DummyPWd";
Also, what does this.SecurePwd() do and have you tried it with just the straight password string that you're passing into it?
I am trying to set environment variable from a console application by executing it from my windows application. I invoke console application and send the value of environment variable as parameter to it, then set the thread to wait for 10 seconds to proceed with next execution.
In the next step i try to load a new .exe which reads the value set to the environment variable.
The exe will not read the new value and continue to refer the value set earlier.
Once the solution of application is closed and open then it reads the new value i.e reload the vshost.
betting you set up the variable only for the current process. You should try this overload of the Environment.SetEnvironmentVariable method :
Environment.SetEnvironmentVariable("YourVar", "YourValue",
EnvironmentVariableTarget.User);
[Edit] Re-Reading your question, you said in the title "same process", and in the question "new exe". In term of Env varialble, spanning a new process implies a new process scope for env variables. They won't share env variables with process scope just because it's the same executable. Maybe you should explain what you are trying to do at a higher level.
[Edit2] not sure to understand why it fails... But you can specify env variable when spawning process using a ProcessStartInfo.EnvironmentVariables Property
Basically, it can be (not tested) :
var psi = new ProcessStartInfo {
FileName="yourExe"
};
psi.EnvironmentVariables.Add("YourVariable","YourValue");
var process = Process.Start(psi);
I am using the following code to fire the iexplore process. This is done in a simple console app.
public static void StartIExplorer()
{
var info = new ProcessStartInfo("iexplore");
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
string password = "password";
SecureString securePassword = new SecureString();
for (int i = 0; i < password.Length; i++)
securePassword.AppendChar(Convert.ToChar(password[i]));
info.UserName = "userName";
info.Password = securePassword;
info.Domain = "domain";
try
{
Process.Start(info);
}
catch (System.ComponentModel.Win32Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The above code is throwing the error The system cannot find the file specified. The same code when run without specifying the user credentials works fine. I am not sure why it is throwing this error.
Can someone please explain?
Try to replace your initialization code with:
ProcessStartInfo info
= new ProcessStartInfo(#"C:\Program Files\Internet Explorer\iexplore.exe");
Using non full filepath on Process.Start only works if the file is found in System32 folder.
You can't use a filename like iexplore by itself because the path to internet explorer isn't listed in the PATH environment variable for the system or user.
However any path entered into the PATH environment variable allows you to use just the file name to execute it.
System32 isn't special in this regard as any directory can be added to the PATH variable. Each path is simply delimited by a semi-colon.
For example I have c:\ffmpeg\bin\ and c:\nmap\bin\ in my path environment variable, so I can do things like new ProcessStartInfo("nmap", "-foo") or new ProcessStartInfo("ffplay", "-bar")
The actual PATH variable looks like this on my machine.
%SystemRoot%\system32;C:\FFPlay\bin;C:\nmap\bin;
As you can see you can use other system variables, such as %SystemRoot% to build and construct paths in the environment variable.
So - if you add a path like "%PROGRAMFILES%\Internet Explorer;" to your PATH variable you will be able to use ProcessStartInfo("iexplore");
If you don't want to alter your PATH then simply use a system variable such as %PROGRAMFILES% or %SystemRoot% and then expand it when needed in code. i.e.
string path = Environment.ExpandEnvironmentVariables(
#"%PROGRAMFILES%\Internet Explorer\iexplore.exe");
var info = new ProcessStartInfo(path);
Also, if your PATH's dir is enclosed in quotes, it will work from the command prompt but you'll get the same error message
I.e. this causes an issue with Process.Start() not finding your exe:
PATH="C:\my program\bin";c:\windows\system32
Maybe it helps someone.
I had the same problem, but none of the solutions worked for me, because the message The system cannot find the file specified can be misleading in some special cases.
In my case, I use Notepad++ in combination with the registry redirect for notepad.exe. Unfortunately my path to Notepad++ in the registry was wrong.
So in fact the message The system cannot find the file specified was telling me, that it cannot find the application (Notepad++) associated with the file type(*.txt), not the file itself.
I know it's a bit old and although this question have accepted an answer, but I think its not quite answer.
Assume we want to run a process here C:\Program Files\SomeWhere\SomeProcess.exe.
One way could be to hard code absolute path:
new ProcessStartInfo(#"C:\Program Files\SomeWhere\SomeProcess.exe")
Another way (recommended one) is to use only process name:
new ProcessStartInfo("SomeProcess.exe")
The second way needs the process directory to be registered in Environment Variable Path variable. Make sure to add it in System Variables instead of Current User Variables, this allows your app to access this variable.
You can use the folowing to get the full path to your program like this:
Environment.CurrentDirectory