Working with environment variables
Environment variables are system and user-definable values that can affect the way running processes behave. They are commonly used to set options like toggling between development and production configurations in ASP.NET Core web projects, or to pass values needed by a process like service keys and passwords for database connection strings.
Environment variables on Windows can be set at three scope levels: machine (aka system), user, and process. The methods for setting and getting environment variables assume process scope level by default and have overloads to specify the EnvironmentVariableTarget
of Process
, User
, and Machine
, as shown in Table 9.7:
Method | Description |
---|---|
GetEnvironmentVariables |
Returns an IDictionary of all environment variables at a specified scope level or for the current process by default. |
GetEnvironmentVariable |
Returns the value for a named environment variable. |
SetEnvironmentVariable |
Sets the value for a named environment variable. |
ExpandEnvironmentVariables |
Converts any environment variables in a string to their values identified with %% . For example, "My computer is named %COMPUTER_NAME%" . |
Table 9.7: Methods to work with environment variables
Let's start by looking at how to list all current environment variables at various levels of scope:
- Use your preferred code editor to add a new Console App /
console
project namedWorkingWithEnvVars
to theChapter09
solution. - In the project file, add a package reference for
Spectre.Console
, and then add elements to statically and globally import theSystem.Console
andSystem.Environment
classes, and finally import the namespaces to work withSpectre.Console
andSystem.Collections
, as shown in the following configuration:
<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.47.0" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
<Using Include="System.Environment" Static="true" />
<Using Include="Spectre.Console" />
<Using Include="System.Collections" />
</ItemGroup>
- Add a new class file named
Program.Helpers.cs
. - In
Program.Helpers.cs
, add apartial Program
class with aSectionTitle
and aDictionaryToTable
method, as shown in the following code:
// null namespace to merge with auto-generated Program.
partial class Program
{
private static void SectionTitle(string title)
{
ConsoleColor previousColor = ForegroundColor;
ForegroundColor = ConsoleColor.DarkYellow;
WriteLine($"*** {title} ***");
ForegroundColor = previousColor;
}
private static void DictionaryToTable(IDictionary dictionary)
{
Table table = new();
table.AddColumn("Key");
table.AddColumn("Value");
foreach (string key in dictionary.Keys)
{
table.AddRow(key, dictionary[key]!.ToString()!);
}
AnsiConsole.Write(table);
}
}
- In
Program.cs
, delete any existing statements, and write statements to show all the environment variables at the three different scopes, as shown in the following code:
SectionTitle("Reading all environment variables for process");
IDictionary vars = GetEnvironmentVariables();
DictionaryToTable(vars);
SectionTitle("Reading all environment variables for machine");
IDictionary varsMachine = GetEnvironmentVariables(
EnvironmentVariableTarget.Machine);
DictionaryToTable(varsMachine);
SectionTitle("Reading all environment variables for user");
IDictionary varsUser = GetEnvironmentVariables(
EnvironmentVariableTarget.User);
DictionaryToTable(varsUser);
- Run the code and view the result, as shown in the following partial output:
*** Reading all environment variables for process ***
┌─────────────────┬──────────────────────────────────────────────────┐
│ Key │ Value │
├─────────────────┼──────────────────────────────────────────────────┤
│ HOMEPATH │ \Users\markj │
...
└─────────────────┴──────────────────────────────────────────────────┘
Often you need to format a string that contains embedded environment variables. They are defined by surrounding the variable name with percent symbols, as shown in the following text:
My username is %USERNAME%. My CPU is %PROCESSOR_IDENTIFIER%.
To set an environment variable at the command prompt on Windows, use the set
or setx
commands, as shown in Table 9.8:
Scope Level | Command |
---|---|
Session/Shell | set MY_ENV_VAR="Alpha" |
User | setx MY_ENV_VAR "Beta" |
Machine | setx MY_ENV_VAR "Gamma" /M |
Table 9.8: Commands to set an environment variable on Windows
The set
command defines a temporary environment variable that can be read immediately in the current shell or session. Note that it uses an equal sign =
to assign the value.
The setx
command defines a permanent environment variable but after defining it, you must close the current shell or session and restart the shell for the environment variable to be read. Note that it does not use an equal sign to assign the value!
More Information: You can learn more about the setx command here: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/setx.
You can also manage environment variables with a user interface on Windows: Navigate to Settings | System | About | Advanced system settings, and then in the System Properties dialog box, click Environment Variables.
To temporarily set an environment variable at the command prompt or terminal on macOS or Linux, you can use the export
command, as shown in the following command:
export MY_ENV_VAR=Delta
More Information: You can learn more about the
export
command here: https://ss64.com/bash/export.html.
Let's see some examples of expanding, setting in various ways, and getting environment variables:
- In
Program.cs
, add statements to define a string that contains a couple of environment variables (if the ones I picked are not defined on your computer, then pick any other two that you do have defined) and then expand them and output them to the console, as shown in the following code:
string myComputer = "My username is %USERNAME%. My CPU is %PROCESSOR_IDENTIFIER%.";
WriteLine(ExpandEnvironmentVariables(myComputer));
- Run the code and view the result, as shown in the following output:
My username is markj. My CPU is Intel64 Family 6 Model 140 Stepping 1, GenuineIntel.
- In
Program.cs
, add statements to set a process scoped environment variable namedMY_PASSWORD
and then get it and output it, as shown in the following code:
string password_key = "MY_PASSWORD";
SetEnvironmentVariable(password_key, "Pa$$w0rd");
string? password = GetEnvironmentVariable(password_key);
WriteLine($"{password_key}: {password}");
- Run the code and view the result, as shown in the following output:
MY_PASSWORD: Pa$$w0rd
In a real-world app, you might pass an argument to the console that is then used to set the process scope environment variable on startup for reading later in the process lifetime.
- In
Program.cs
, add statements to try to get an environment variable namedMY_PASSWORD
at all three potential scope levels, and then output them, as shown in the following code:
string secret_key = "MY_SECRET";
string? secret = GetEnvironmentVariable(secret_key,
EnvironmentVariableTarget.Process);
WriteLine($"Process - {secret_key}: {secret}");
secret = GetEnvironmentVariable(secret_key,
EnvironmentVariableTarget.Machine);
WriteLine($"Machine - {secret_key}: {secret}");
secret = GetEnvironmentVariable(secret_key,
EnvironmentVariableTarget.User);
WriteLine($"User - {secret_key}: {secret}");
- If you are using Visual Studio 2022, then navigate to Project | WorkingWithEnvVars Properties, click the Debug tab, and then click Open debug launch profiles UI. In the Environment variables section, add an entry with Name
MY_SECRET
and Value ofAlpha
. - In the
Properties
folder, openlaunchSettings.json
, and note the configured environment variables, as shown in the following configuration:
{
"profiles": {
"WorkingWithEnvVars": {
"commandName": "Project",
"environmentVariables": {
"MY_SECRET": "Alpha"
}
}
}
}
If you are using a different code editor, then you can manually create the
launchSettings.json
file. Environment variables defined in thelaunchSettings.json
file are set at process scope.
- At the command prompt or terminal with administrator permissions, set some environment variables at the user and machine scope levels on Windows, as shown in the following commands:
setx MY_SECRET "Beta"
setx MY_SECRET "Gamma" /M
- Note the result for each command, as shown in the following output:
SUCCESS: Specified value was saved.
On macOS or Linux, use the
export
command instead.
- Run the code and view the result, as shown in the following output:
Process - MY_SECRET: Alpha
Machine - MY_SECRET: Gamma
User - MY_SECRET: Beta
Now that you have seen how to work with environment variables, we can use them in future chapters to set options like passwords rather than store those sensitive values in code.