更改调用进程的环境变量

发布于 2024-11-08 18:23:39 字数 815 浏览 4 评论 0原文

这看起来微不足道,但我已经好几天没有找到答案了。

我有一个 Windows 批处理文件,它调用 C# 程序来执行批处理文件中无法完成的额外验证。验证完成后,我需要将状态和字符串返回给调用 shell。

现在返回值很简单,我的 C# 控制台应用程序只需设置一个返回值(如果愿意,请退出代码)。我认为字符串也将是小菜一碟。我尝试使用以下方法定义一个新的 shell 变量:

Environment.SetEnvironmentVariable("ERR", "Some text");

此调用应该(并且确实)在当前进程中定义一个 shell 变量 - 即创建该变量的 C# 进程。一旦 C# 应用程序终止,并且创建 C# 应用程序的 shell 对变量一无所知,该值就会丢失。所以...没有特殊用途的调用...根本...除非我从 C3 应用程序创建了一个子进程,否则它可能会继承我的变量。

SetEnvironmentVariable 调用的EnvironmentVariableTarget.Machine 和EnvironmentVariableTarget.User 目标也不能解决问题,因为只有新创建的进程才会从注册表中获取这些新值。

所以我能想到的唯一可行的解​​决方案是:

  • 写入标准输出
  • 写入文件
  • 将额外的含义编码到返回值中

前两个有点难看,最后一个有其局限性和问题。

还有其他想法(如何在父进程中设置 shell 变量)?也许这样的 shell 变量修改是一个安全问题(想想 PATH)...

谢谢您的宝贵时间。

This one seems trivial but the answer has eluded me for a few days now.

I have a Windows batch file, that calls a C# program to do an extra verification that cannot be done in a batch file. After the verification is complete I need to return a status and a string back to the calling shell.

Now the return value is trivial and my C# console app simply sets a return value (exit code if you will). And I thought the string will also be a piece of cake. I attempted to define a new shell variable using the:

Environment.SetEnvironmentVariable("ERR", "Some text");

This call should (and does) define a shell variable within the current process - that is the very C# process that created the variable. The value is lost as soon as the C# app terminates and the shell that created the C# app knows nothing about the variable. So... A call with no particular use... At all... Unless perhaps if I created a child process from the C3 app, perhaps it would inherit my variables.

The EnvironmentVariableTarget.Machine and EnvironmentVariableTarget.User targets for the SetEnvironmentVariable call don't solve the problem either, as only a newly created process will get these new values from the registry.

So the only working solution I can think of is:

  • write to stdout
  • write to a file
  • encode extra meaning into the return value

The first two are a bit ugly and the last one has its limitations and problems.

Any other ideas (how to set a shell variable in the parent process)? Maybe such shell variable modifications are a security concern (think PATH)...

Thank-you for your time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

南风几经秋 2024-11-15 18:23:39

我遇到了与 Ryan 相同的问题,我想到的唯一解决方法是编写一个错误的批处理来设置变量并从批处理中调用它。

ConsoleApplication1.exe:

'put some sensible code here
'put result in variable myResult
Dim myResult As String = Guid.NewGuid().ToString("D").ToUpperInvariant()
Console.WriteLine("Normal output from the consonle app")
Console.Error.WriteLine("@ECHO OFF")
Console.Error.WriteLine("SET zzzResult={0}", myResult)

Test.cmd(调用批处理):

@ECHO OFF
:Jump to folder of batch file
PUSHD %~d0%~p0

:Define a temp file
SET zzzTempFile=%TEMP%\TMP%Random%.CMD

:Call .NET console app
ConsoleApplication1.exe 2>%zzzTempFile%

:Call the generated batch file
CALL %zzzTempFile%

:Clean up temp file
DEL %zzzTempFile%

:Clean up variable
SET zzzTempFile=

:Do something with the result
ECHO Yeah, we finally got it!
ECHO:
ECHO The value is "%zzzResult%".
ECHO:

:Clean up result variable
SET zzzResult=

:Go back to original folder
POPD

这应该可以解决问题。是的,我确实知道这是一篇旧帖子,瑞安现在正在解决其他问题,但可能还有其他人遇到同样的问题......

I had the same problem as Ryan and the only thing that came to my mind as a work-around was to write a batch in error out to set the variable and to call it from the batch.

ConsoleApplication1.exe:

'put some sensible code here
'put result in variable myResult
Dim myResult As String = Guid.NewGuid().ToString("D").ToUpperInvariant()
Console.WriteLine("Normal output from the consonle app")
Console.Error.WriteLine("@ECHO OFF")
Console.Error.WriteLine("SET zzzResult={0}", myResult)

Test.cmd (the calling batch):

@ECHO OFF
:Jump to folder of batch file
PUSHD %~d0%~p0

:Define a temp file
SET zzzTempFile=%TEMP%\TMP%Random%.CMD

:Call .NET console app
ConsoleApplication1.exe 2>%zzzTempFile%

:Call the generated batch file
CALL %zzzTempFile%

:Clean up temp file
DEL %zzzTempFile%

:Clean up variable
SET zzzTempFile=

:Do something with the result
ECHO Yeah, we finally got it!
ECHO:
ECHO The value is "%zzzResult%".
ECHO:

:Clean up result variable
SET zzzResult=

:Go back to original folder
POPD

That should do the trick. And yes, I do know this is an old post and Ryan is solving other issues by now, but there might be still somebody else out there having the same problem...

蓝海 2024-11-15 18:23:39

您要求的是能够任意写入正在运行的进程的内存空间。出于充分的理由,如果没有 SeDebugPrivilege,这是不可能的。

您列出的三种解决方案中的任何一种都可以。 Stdout 是与批处理脚本通信的标准方式。

顺便说一句,您正在编写一个 Windows 批处理文件。我很确定这艘船已经“有点丑陋”地航行了。

What you are asking is to be able to arbitrarily write to the memory space of a running process. For good reason, this is not possible without SeDebugPrivilege.

Any of the three solutions you list will work. Stdout is the standard way to communicate with a batch script.

By the way, you're writing a Windows batch file. I'm pretty sure the ship has already sailed on "a bit ugly".

美胚控场 2024-11-15 18:23:39

如果您想将某些输出的值放入批处理中的变量中,您可以使用以下构造:

FOR /F "usebackq tokens=4 delims=\[\] " %i IN (`ver`) DO set VERSION=%i
ECHO %VERSION%

我的操作系统上的输出:

6.1.7601

“usebackq”意味着我们正在使用反引号,这使得能够在用引号引起来的命令中使用文件集双引号。你可能不需要这个。 'tokens' 表示要选择的结果字符串数组中的索引(可以是范围 MN)。如果您需要跳过行,请使用“skip=X”)。 'delims' 是要使用的字符串分隔符(如 .Net 中的 string-Split())。

您将放置控制台应用程序而不是“ver”,并调整分隔符和标记以匹配您的特定输出。如果您有更多变量需要填充,您将需要使 if 更复杂一些,但这应该是一个良好的开始。

If you want to put a value of some output into a variable in the batch you can use the following construct:

FOR /F "usebackq tokens=4 delims=\[\] " %i IN (`ver`) DO set VERSION=%i
ECHO %VERSION%

Output on my OS:

6.1.7601

'usebackq' means we are using back quotes which gives the ability to use a fileset in the command quoted with double quotes. You may not need this. 'tokens' means the index in the resulting string array to select (it can be a range M-N). If you need to skip lines use 'skip=X'). 'delims' are the string separators to use (like string-Split() in .Net).

You will put your console app instead of 'ver' and adapt the delimiters and tokens to match your specific output. If you have more variables to fill you will need to make the if a bit more complex but that should make a good start.

无可置疑 2024-11-15 18:23:39

我的 BAT 有点生疏,但我认为可以从外部运行的进程中检索“退出”代码,也许可以通过 %ERRORLEVEL% 来获取。如果是这种情况,请确保通过

Environment.Exit(123); // where 123 = error code

“您无法添加任何消息”退出程序,因此您必须在 .bat 文件中执行此操作。

如果不是这种情况,stdout 可能是最好的方法。

My BAT is a bit rusty, but I think it's possible to retrieve the 'exit' code from processes you've run externally, perhaps via %ERRORLEVEL%. If that's the case, make sure to exit your program via

Environment.Exit(123); // where 123 = error code

You can't add any messages, so you'll have to do that in the .bat file.

If this isn't the case, stdout is probably the best way.

画中仙 2024-11-15 18:23:39

最近我自己也偶然发现了这一点,然后我想出了这种方法。我所做的是使用 Process 类运行 bat 文件,即

// Spawn your process as you normally would... but also have it dump the environment varaibles
Process process = new Process();
process.StartInfo.FileName = mybatfile.bat;
process.StartInfo.Arguments = @"&&set>>envirodump.txt";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();

// Read the environment variable lines into a string array
string[] envirolines = File.ReadAllLines("envirodump.txt");
File.Delete("envirodump.txt");

// Now simply set the environment variables in the parent process
foreach(string line in a)
{
    string var = line.Split('=')[0];
    string val = line.Split('=')[1];
    Environment.SetEnvironmentVariable(var, val);
} 

这似乎对我有用。这不是最干净的方法,但会在绑定中起作用。 :)

After stumbling on this myself as well recently, I came up with this approach. What I did is run the bat file using the Process class, i.e.

// Spawn your process as you normally would... but also have it dump the environment varaibles
Process process = new Process();
process.StartInfo.FileName = mybatfile.bat;
process.StartInfo.Arguments = @"&&set>>envirodump.txt";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();

// Read the environment variable lines into a string array
string[] envirolines = File.ReadAllLines("envirodump.txt");
File.Delete("envirodump.txt");

// Now simply set the environment variables in the parent process
foreach(string line in a)
{
    string var = line.Split('=')[0];
    string val = line.Split('=')[1];
    Environment.SetEnvironmentVariable(var, val);
} 

This seems to have worked for me. It's not the cleanest approach, but will work in a bind. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文