34

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:

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 t is empty.

Any idea why?

David d C e Freitas
  • 7,481
  • 4
  • 58
  • 67
Brian
  • 461
  • 1
  • 4
  • 6

10 Answers10

51

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

Create a REG_MULTI_SZ called Environment.

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.

Instead, you use the key ...

HKLM\SYSTEM\CurrentControlSet\Services\YourService\Parameters

and create a REG_MULTI_SZ called AppEnvironment

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).

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.

Regards,

Richard.

25

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 environment does not recognize this until it "restarts". This is because these environment variables are stored in the registry and this registry is read only once by 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 KB on this.

Scott Saad
  • 17,962
  • 11
  • 63
  • 84
  • 3
    But note that this is only true for services running under the local system account. For services that run under a specified user account, they *will* pick up environment changes from the registry after restart. – Martin Ba Jun 30 '11 at 14:58
6

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

EBGreen
  • 36,735
  • 12
  • 65
  • 85
  • I guess I should have clarified this, but TIP_HOME is a system variable. I thought system variables were NOT user-specific? – Brian Nov 20 '08 at 16:22
  • 1
    Well, as a test you can add debuging code to your service to have it iterate through all the environment vars it sees at startup and output those to a temp file. – EBGreen Nov 20 '08 at 16:26
3

Are you running the service under the Local System account?

Have you restarted the machine after adding the TIP_HOME variable?

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

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • Yes, the machine has been restarted since the system variable was set. I am creating and launching the service under the Administrator account. – Brian Nov 20 '08 at 17:33
  • https://web.archive.org/web/20100306183453/http://support.microsoft.com/kb/821761 – gavenkoa Dec 31 '20 at 14:57
1

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

MANASA
  • 11
  • 1
1

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

Environment.GetEnvironmentVariable Method (String, EnvironmentVariableTarget)

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

  • Machine (available for all users)
  • User (available for the current user)
  • Process (available only for the current Process [not recommended btw])

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

Hope it helps :)

lucas
  • 75
  • 2
  • 7
1

Services typically are run under one of three service accounts, Local Service Local System and Network Service. For all of which your typical environmental variable will be 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#:

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

Joseph
  • 151
  • 4
1

Are you aware of system and user environment variables? A Windows Service, by default, runs under the system account.

Steve Dunn
  • 21,044
  • 11
  • 62
  • 87
  • Yes, the variable I am looking for is a system variable. See the answer I posted below. – Brian Nov 20 '08 at 16:41
1

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:

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);
}
Brian
  • 461
  • 1
  • 4
  • 6
0

I modified that line of code to this:

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

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

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.

User variables are stored elsewhere in the registry..

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

Brian
  • 461
  • 1
  • 4
  • 6