C# 从 Windows 服务访问环境变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/305870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 22:28:46  来源:igfitidea点击:

Accessing Environment Variables from Windows Services

c#windows-servicespermissions

提问by Brian

I am attempting to write a Windows Service in C#. I need to find the path to a certain file, which is stored in an environment variable. In a regular C# console application, I can achieve that with the following line:

我正在尝试用 C# 编写 Windows 服务。我需要找到某个文件的路径,该文件存储在环境变量中。在常规的 C# 控制台应用程序中,我可以使用以下行来实现:

string t = System.Environment.GetEnvironmentVariable("TIP_HOME");

If I write that to the console I see that it was successful.

如果我将其写入控制台,我会看到它成功了。

Now, if I try that same code in a Windows Service, the string tis empty.

现在,如果我在 Windows 服务中尝试相同的代码,则字符串t为空。

Any idea why?

知道为什么吗?

回答by EBGreen

The service is probably running under a different account and is not getting the same environment variables.

该服务可能在不同的帐户下运行,并且没有获得相同的环境变量。

回答by Steve Dunn

Are you aware of systemand userenvironment variables? A Windows Service, by default, runs under the systemaccount.

您是否了解系统用户环境变量?默认情况下,Windows 服务在系统帐户下运行。

回答by Brian

I modified that line of code to this:

我将那行代码修改为:

string t = System.Environment.GetEnvironmentVariable("TIP_HOME", EnvironmentVariableTarget.Machine);

string t = System.Environment.GetEnvironmentVariable("TIP_HOME", EnvironmentVariableTarget.Machine);

I can look through my registry and see that TIP_HOME is set.

我可以查看我的注册表并看到 TIP_HOME 已设置。

This is from MSDN: Machine: The environment variable is stored or retrieved from the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment key in the Windows operating system registry.

这是来自 MSDN:机器:环境变量是从 Windows 操作系统注册表中的 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment 项存储或检索的。

User variables are stored elsewhere in the registry..

用户变量存储在注册表的其他地方。

The string is still showing up empty when I run the service with this change, though.

但是,当我使用此更改运行服务时,该字符串仍显示为空。

回答by Scott Saad

Your problem seems to be something like we've experienced and can be very tricky to figure out what's going on.

您的问题似乎与我们经历过的类似,并且很难弄清楚发生了什么。

What happens is when environment variables are added/removed/changed, the services environmentdoes not recognize this until it "restarts". This is because these environment variables are stored in the registry and this registry is read only onceby the service environment... at system startup.

发生的情况是,当添加/删除/更改环境变量时,服务环境在“重新启动”之前无法识别这一点。这是因为这些环境变量存储在注册表中,并且该注册表被服务环境读取一次...在系统启动时

This means that in order for a service to pickup a change in environment variables, a system restart needs to occur.

这意味着为了让服务在环境变量中发生变化,需要重新启动系统。

Check out the Microsoft KBon this.

请查看Microsoft KB

回答by Brian

Okay, I don't quite understand this, but here is what I've found..

好吧,我不太明白这一点,但这是我发现的..

In the same service, I first try what I described earlier and the string returns empty.

在同一个服务中,我首先尝试我之前描述的内容,字符串返回空。

Then, if I enumerate through each of the system-level environment variables, it finds the variable I am looking for just fine.

然后,如果我枚举每个系统级环境变量,它会很好地找到我正在寻找的变量。

Here is a code snippet, slightly modified from some sample code found on MSDN:

这是一个代码片段,从 MSDN 上找到的一些示例代码稍作修改:

foreach(DictionaryEntry de in Environment.GetEnvironmentVariables(tgt))
{
    key   = (string)de.Key;
    value = (string)de.Value;

    if(key.Equals("TIP_HOME") && value != null)
        log.WriteEntry("TIP_HOME="+value, EventLogEntryType.Information);
}

回答by Michael Burr

Are you running the service under the Local System account?

您是否在本地系统帐户下运行该服务?

Have you restarted the machine after adding the TIP_HOME variable?

添加 TIP_HOME 变量后是否重新启动了机器?

Services running under Local System get started from the services.exe service, which only reads its environment when it starts up: http://support.microsoft.com/kb/821761

在Local System下运行的服务从services.exe服务开始,它只在启动时读取其环境:http: //support.microsoft.com/kb/821761

回答by MANASA

try this code string getsyspath = System.Environment.GetEnvironmentVariable("TIP_HOME",EnvironmentVariableTarget.Machine);

试试这个代码字符串 getsyspath = System.Environment.GetEnvironmentVariable("TIP_HOME",EnvironmentVariableTarget.Machine);

回答by Richard Quadling

I've no idea if this is useful, but I've found that for every service, there is an option to add environment variables directly to a service.

我不知道这是否有用,但我发现对于每个服务,都有一个选项可以将环境变量直接添加到服务中。

It is done via the registry.

它是通过注册表完成的。

Say the key to your service is ...

说你的服务的关键是......

HKLM\SYSTEM\CurrentControlSet\Services\YourService

HKLM\SYSTEM\CurrentControlSet\Services\YourService

Create a REG_MULTI_SZ called Environment.

创建一个名为 Environment 的 REG_MULTI_SZ。

Now you can add entries like ...

现在您可以添加条目,例如...

Var1=Value1
Var2=Value2

and these will be available to the service code.

这些将可用于服务代码。

If you are using the Windows Resource ToolKit to install scripts as a service (instsrv.exe and srvany.exe), then, again, you have the option of setting Environment variables for the service, but most likely it is the wrong one as these would be for srvany.exe.

如果您使用 Windows Resource ToolKit 将脚本安装为服务(instsrv.exe 和 srvany.exe),那么您同样可以选择为服务设置环境变量,但很可能是错误的,因为这些将用于 srvany.exe。

Instead, you use the key ...

相反,您使用密钥...

HKLM\SYSTEM\CurrentControlSet\Services\YourService\Parameters

HKLM\SYSTEM\CurrentControlSet\Services\YourService\Parameters

and create a REG_MULTI_SZ called AppEnvironment

并创建一个名为 AppEnvironment 的 REG_MULTI_SZ

Set the entries in the same way.

以相同的方式设置条目。

And now your script service has it's own environment variables.

现在你的脚本服务有它自己的环境变量。

I'm using these techniques with PHP+WinCache to allow me to set an APP_POOL_ID unique to each service which allows WinCache to share a central cache (based upon APP_POOL_ID) for all "threads" (using WShell to launch non-blocking child "threads" and still share the same WinCache as the launcher, allowing simplistic, inter-process communication).

我将这些技术与 PHP+WinCache 一起使用,以允许我为每个服务设置唯一的 APP_POOL_ID,这允许 WinCache 为所有“线程”共享中央缓存(基于 APP_POOL_ID)(使用 WShell 启动非阻塞子“线程” "并且仍然与启动器共享相同的 WinCache,允许简单的进程间通信)。

Anyway. I hope this helps somewhat.

反正。我希望这会有所帮助。

I think, in the main, you aren't adding unnecessary env_vars to the global environment. You can keep them targetted and unique when you have more than 1.

我认为,主要是您没有向全局环境添加不必要的 env_vars。当您拥有超过 1 个时,您可以使它们具有针对性和独特性。

Regards,

问候,

Richard.

理查德.

回答by lucas

You need to check how the variable was stored. There's the overload method for the Set/GetEnvironmentVariable:

您需要检查变量的存储方式。Set/GetEnvironmentVariable 有重载方法:

Environment.GetEnvironmentVariable Method (String, EnvironmentVariableTarget)

Environment.GetEnvironmentVariable 方法(字符串,EnvironmentVariableTarget)

The thing is, there are three types of storing the environment variable (EnvironmentVariableTarget):

问题是,有三种类型的存储环境变量(EnvironmentVariableTarget):

  • Machine (available for all users)
  • User (available for the current user)
  • Process (available only for the current Process [not recommended btw])
  • 机器(适用于所有用户)
  • 用户(当前用户可用)
  • 进程(仅适用于当前进程 [不推荐 btw])

If you store the information as Machine or User, then you can test it as running Run (Win + R): %TIP_HOME%

如果您将信息存储为 Machine 或 User,那么您可以将其测试为运行 Run (Win + R): %TIP_HOME%

Hope it helps :)

希望能帮助到你 :)

回答by Joseph

Services typically are run under one of three service accounts, Local ServiceLocal Systemand Network Service. For all of which your typical environmental variable will be null.

服务通常在三个服务帐户之一下运行,Local ServiceLocal System并且Network Service. 对于所有这些,您的典型环境变量将为null



To Investigate

去弄清楚



I tested by having the service write an event log entry, and print what it stores in the HOMEPATH variable. It returned empty for service accounts. In C#:

我通过让服务写入事件日志条目进行测试,并打印它在 HOMEPATH 变量中存储的内容。它为服务帐户返回空。在 C# 中:

protected override void OnStart(string[] args)
{
    EventLog.WriteEntry("The HomePath for this service is '" + Environment.GetEnvironmentVariable("HOMEPATH") + "'", EventLogEntryType.Information);
}


Possible Solutions

可能的解决方案



You can set what account a service uses (your user account for instance), in the services properties window or in the service install config. When I tested with my user account the event log entry displayed The HomePath for this service is '\Users\Admin-PC'. If it were using your user account it would have access to all of the environmental variables that you typically have access to.
enter image description here. enter image description here

您可以在服务属性窗口或服务安装配置中设置服务使用的帐户(例如您的用户帐户)。当我使用我的用户帐户进行测试时,显示的事件日志条目The HomePath for this service is '\Users\Admin-PC'。如果它使用您的用户帐户,它将有权访问您通常有权访问的所有环境变量。
在此处输入图片说明. 在此处输入图片说明