Use PowerShell to Persist Environment Variables

In PowerShell, you can easily create environment variables using a few different methods. However, these are only scoped to the current PowerShell process, and not to any process running inside the user’s profile, or any process running on the system.

Here are a few examples of methods that you can use to set environment variables in PowerShell.

### Use the variable syntax to create a new environment variable
$env:FirstName = 'Trevor'

### Use the built-in env: PSDrive
New-Item -Path env:\LastName -Value Sullivan

### Set an environment variable using the System.Environment .NET class
[System.Environment]::SetEnvironmentVariable('DOCKER_HOST', 'docker.artofshell.com')

Each of the examples above will set an environment variable for the scope of the current process. Once that process dies, the environment variables disappear, and must be set again. So the question becomes: how do I persist environment variables in the user profile or for the entire system?

In fact, the answer isn’t too far off from the last example above! We still will leverage the SetEnvironmentVariable static method on the System.Environment class. However, there’s a method overload that takes a third input parameter of type [System.EnvironmentVariableTarget], which is a .NET enumeration. We can discover the supported values on this enumeration, by simply piping it into Get-Member -Static.

PS C:\Users\TrevorSullivan> [System.EnvironmentVariableTarget] | Get-Member -Static


   TypeName: System.EnvironmentVariableTarget

Name              MemberType Definition
----              ---------- ----------
Equals            Method     static bool Equals(System.Object objA, System.Object objB)
Format            Method     static string Format(type enumType, System.Object value, string format)
GetName           Method     static string GetName(type enumType, System.Object value)
GetNames          Method     static string[] GetNames(type enumType)
GetUnderlyingType Method     static type GetUnderlyingType(type enumType)
GetValues         Method     static array GetValues(type enumType)
IsDefined         Method     static bool IsDefined(type enumType, System.Object value)
Parse             Method     static System.Object Parse(type enumType, string value), static System.Object Parse(typ...
ReferenceEquals   Method     static bool ReferenceEquals(System.Object objA, System.Object objB)
ToObject          Method     static System.Object ToObject(type enumType, System.Object value), static System.Object...
TryParse          Method     static bool TryParse[TEnum](string value, [ref] TEnum result), static bool TryParse[TEn...
Machine           Property   static System.EnvironmentVariableTarget Machine {get;}
Process           Property   static System.EnvironmentVariableTarget Process {get;}
User              Property   static System.EnvironmentVariableTarget User {get;}

As you can see in the above output, the [System.EnvironmentVariableTarget] enumeration supports three values:

  • Machine
  • Process
  • User

Now let’s take a look at the method overload for the [System.Environment]::SetEnvironmentVariable() method.

PS C:\Users\TrevorSullivan> [System.Environment]::SetEnvironmentVariable

OverloadDefinitions
-------------------
static void SetEnvironmentVariable(string variable, string value)
static void SetEnvironmentVariable(string variable, string value, System.EnvironmentVariableTarget target)

As you can see, we have two method overloads to choose from. In the very first example, we used the first method overload, which only takes two input parameters: the environment variable name, and the value we want to set it to. The other method overload allows us to specify a target for the environment variable! Let’s take a quick look at how to utilize it.

PS C:\Users\TrevorSullivan> [System.Environment]::SetEnvironmentVariable('DOCKER_HOST', 'tcp://docker.artofshell.com:2376
', [System.EnvironmentVariableTarget]::User)

Well, that’s a bit of a long command line, but it achieves what we are interested in: setting an environment variable persistently for our user profile. The next time we log into the system, with the same user account, that environment variable will still be set. We can verify this by using the System Properties GUI for exploring environment variables:

  • Press WINDOWS + X, then Y
  • In the System window, click the Change settings link
  • In the System Properties window, choose the Advanced tab
  • Click the Environment Variables button

Windows 10 Environment Variables

Great, that worked! So what if we tried to set a system-wide environment variable? To do that, all we need to do is change the “target” of the environment variable to Machine. If you’re not running PowerShell “as Administrator,” you might receive an error message though.

PS C:\Users\TrevorSullivan> [System.Environment]::SetEnvironmentVariable('DOCKER_HOST', 'tcp://docker.artofshell.com:2376', [System.EnvironmentVariableTarget]::Machine)
Exception calling "SetEnvironmentVariable" with "3" argument(s): "Requested registry access is not allowed."
At line:1 char:1
+ [System.Environment]::SetEnvironmentVariable('DOCKER_HOST', 'tcp://do ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SecurityException

If you do end up getting the error message shown above, just open an elevated PowerShell prompt, and the command should run successfully.