Win32_Environment

The class Win32_Environment represents an environment or system environment setting on a Windows computer system.

Environment variables can store string information. There are personal (“user”) environment variables and common (“system”) environment variables. In addition, environment variables can be handed from one application to another when one application launches the other (“process”).

PowerShell merges environment variables from all sources and provides access via its drive env::

# list all environment variables:
Get-ChildItem -Path env:

# list specific environment variables:
Get-ChildItem -Path *user*

# read content of one environment variable:
$env:windir

In essence, the drive env: exposes the process environment variables. While they can be changed, any change occurs in the process set only and is not persistent. There is also no way for a user to know where a particular environment variable originated and whether it is a user or system variable.

The WMI class Win32_Environment manages user and system environment variables but does not care about process environment variables (the merged and copied set of environment variables applications like PowerShell use). Querying this class returns environment variables found in HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Sessionmanager\Environment and HKEY_USERS<USERSID>\Environment.

Examples

To list all environment variables, run this:

Get-CimInstance -ClassName Win32_Environment

To retrieve a specific environment variable by Name, use a filter:

# the variable must exist!
$name = 'windir'
$variable = Get-CimInstance -ClassName Win32_Environment -Filter "Name='$name'"

New Environment Variables

To create a new environment variable for your current user account, instantiate a new instance via New-CimInstance:

# create username for current user
$username = '{0}\{1}' -f $env:USERDOMAIN, $env:USERNAME

# define initial values to create a new instance of
# Win32_Environment (new environment variable)
$initialValues = @{
    Name = 'SomeInfo'
    VariableValue = '123'
    UserName = $username
}

# create new instance
$newEnv = New-CimInstance -ClassName Win32_Environment -Property $initialValues 

$newEnv

When you add a new environment variable, this will not affect the drive env: for PowerShell sessions that are already running. Only PowerShell sessions launched after you added the new environment variable will pick it up.

This is because the drive env: lists the process environment variables only: these are created only during program launch. In other words: the process environment variables are a snapshot of the environment variables at the time when the process was launched.

Change Environment Variable

To change the value of a environment variable, change its property Name and write back the changes using Set-CimInstance:

# get the environment variable "SomeInfo"
# NOTE: this variable must exist! Use previous example to create it.
$variable = Get-CimInstance -ClassName Win32_Environment -Filter 'Name="SomeInfo"'

$variable.VariableValue

# assign a new property value:
$variable.VariableValue = "NEW"

# Update the change:
$variable | Set-CimInstance

WARNING: Changing environment variables can damage Windows or other installed software products. Be careful and use your own testing environment variables.

Changes to environment variables will not surface in the PowerShell drive env: for any already running PowerShell session. As explained earlier, the drive env: is a copy of the environment variables taken at the time when PowerShell was launched.

Remove Environment Variable

To permanently remove a environment variable, remove its instance

# remove environment variable 'SomeInfo'
Remove-CimInstance -Query 'Select * From Win32_Environment Where Name="SomeInfo"'

WARNING: This command removes the environment variable from the Windows Registry only.

The removed environment variable may still be available in the process sets of running applications, including Windows Explorer. So when you launch a new program after you removed a environment variable, the removed environment variable may still be visible in the newly launched program.

Try yourself: when you launch a new PowerShell session after you deleted a environment variable via WMI, the variable is still visible from within the newly launched PowerShell session:

# list all environment variables that start with "some":
Get-ChildItem -Path env:some*

When you remove environment variables via the official Windows API and the method SetEnvironmentVariable(), this method performs additional steps to clean up the Windows Explorer cache so the removed environment variable becomes unavailable immediately:

# delete environment variable 'SomeInfo' immediately, assuming the variable
# currently exists and was defined in "user" context:
[Environment]::SetEnvironmentVariable('SomeInfo',$null,'user')

This is because SetEnvironmentVariable() (and many other methods) broadcast a message to all open software, indicating that there has been a change in environment variables, asking all running programs to update their environment variables:

Win32Native.SendMessageTimeout(new IntPtr(65535), 26, IntPtr.Zero, "Environment", 0u, 1000u, IntPtr.Zero);

When you remove an instance of Win32_Environment, you are not sending this broadcast message. You can use Update-EnvironmentVariableExplorer to send the broadcast message:

function Update-EnvironmentVariableExplorer
{
  $pInvoke =  '[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
              public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);'
  
  Add-Type -Namespace Win32 -Name Native -MemberDefinition $pInvoke

  $HWND_BROADCAST = [IntPtr]0xffff
  $WM_SETTINGCHANGE = 0x1a
  $result = [UIntPtr]::Zero

  [Win32.Native]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [UIntPtr]::Zero, "Environment", 0, 1000, [ref] $result)
}

Methods

Win32_Environment has 1 methods:

| Method | Description | | ———————- | ———– |

Learn more about Invoke-CimMethod and how to invoke commands. Click any of the methods listed above to learn more about their purpose, parameters, and return value.

Properties

Win32_Environment returns 8 properties:

'Caption','Description','InstallDate','Name','Status','SystemVariable','UserName',
'VariableValue'

Unless explicitly marked as WRITEABLE, all properties are read-only.

Caption

STRING MAX 64 CHAR

A short textual description of the object.

# returning class instances:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, Caption

# reading property value:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, Caption | Foreach-Object {

  $Name = $_.Name
  $value = $_.Caption
  "${Name}: Caption = $value"
}

Description

STRING

A short textual description of the object.

# returning class instances:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, Description

# reading property value:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, Description | Foreach-Object {

  $Name = $_.Name
  $value = $_.Description
  "${Name}: Description = $value"
}

InstallDate

DATETIME

Not supported, always empty.

# returning class instances:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, InstallDate

# reading property value:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, InstallDate | Foreach-Object {

  $Name = $_.Name
  $value = $_.InstallDate
  "${Name}: InstallDate = $value"
}

Name

KEY PROPERTY STRING

Character string that specifies the name of a Windows-based environment variable.

Example: “Path”

# returning class instances:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName

# reading property value:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, Name | Foreach-Object {

  $Name = $_.Name
  $value = $_.Name
  "${Name}: Name = $value"
}

Status

BOOL MAX 10 CHAR

Current status of an object. Various operational and nonoperational statuses can be defined.

Available values:

'Degraded','Error','Lost Comm','No Contact','NonRecover','OK','Pred Fail','Service','Starting','Stopping','Stressed','Unknown'
# returning class instances:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, Status

# filtering all instances with Status set to $true:
Get-CimInstance -ClassName Win32_Environment | Where-Object Status -eq $true | Select-Object -Property Name, UserName, Status

SystemVariable

BOOL MAX CHAR

Indicates whether the variable is a system variable. A system variable applies to all users and can only be set or changed with Administrator privileges.

# returning class instances:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, SystemVariable

# filtering all instances with SystemVariable set to $true:
Get-CimInstance -ClassName Win32_Environment | Where-Object SystemVariable -eq $true | Select-Object -Property Name, UserName, SystemVariable

UserName

KEY PROPERTY STRING MAX 260 CHAR

Name of the owner of the environment setting. It is set to for settings that are specific to the Windows-based system (as opposed to a specific user) and for default user settings.

# returning class instances:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName

# reading property value:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, UserName | Foreach-Object {

  $Name = $_.Name
  $value = $_.UserName
  "${Name}: UserName = $value"
}

VariableValue

WRITEABLE STRING

Value of environment variable.

# returning class instances:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, VariableValue

# reading property value:
Get-CimInstance -ClassName Win32_Environment | Select-Object -Property Name, UserName, VariableValue | Foreach-Object {

  $Name = $_.Name
  $value = $_.VariableValue
  "${Name}: VariableValue = $value"
}

CDXML Definition

You can turn this WMI class and its methods into PowerShell cmdlets by importing below CDXML file (Cmdlet Definition XML) as a module.

Create Win32_Environment.cdxml
$folder = "c:\wmi\Win32_Environment"
$cdxmlPath = Join-Path -Path $folder -ChildPath "Win32_Environment.cdxml"

# create folder if not present:
$exists = Test-Path -Path $folder
if (!$exists) { $null = New-Item -Path $folder -ItemType Directory }

# write file
$content = @'
<?xml version="1.0" encoding="utf-8"?>


<!--
This file is licensed under 'Attribution 4.0 International' license (https://creativecommons.org/licenses/by/4.0/).

You can free of charge use this code in commercial and non-commercial code, and you can freely modify and adjust the code 
as long as you give appropriate credit to the original author Dr. Tobias Weltner.

This material was published and is maintained here: 

https://powershell.one/wmi/root/cimv2/win32_environment#cdxml-definition
-->


<PowerShellMetadata xmlns="http://schemas.microsoft.com/cmdlets-over-objects/2009/11">
  <!--referencing the WMI class this cdxml uses-->
  <Class ClassName="Root/CIMV2\Win32_Environment" ClassVersion="2.0">
    <Version>1.0</Version>
    <!--default noun used by Get-cmdlets and when no other noun is specified. By convention, we use the prefix "WMI" and the base name of the WMI class involved. This way, you can easily identify the underlying WMI class.-->
    <DefaultNoun>WmiEnvironment</DefaultNoun>
    <!--define the cmdlets that work with class instances.-->
    <InstanceCmdlets>
      <!--query parameters to select instances. This is typically empty for classes that provide only one instance-->
      <GetCmdletParameters>
        <QueryableProperties>
          <Property PropertyName="Name">
            <Type PSType="system.string" />
            <RegularQuery AllowGlobbing="false">
              <CmdletParameterMetadata IsMandatory="false" />
            </RegularQuery>
          </Property>
        </QueryableProperties>
      </GetCmdletParameters>
      <GetCmdlet>
        <CmdletMetadata Verb="Get" />
        <GetCmdletParameters>
          <QueryableProperties>
            <Property PropertyName="Description">
              <Type PSType="system.string" />
              <RegularQuery AllowGlobbing="true">
                <CmdletParameterMetadata IsMandatory="false" />
              </RegularQuery>
            </Property>
            <Property PropertyName="InstallDate">
              <Type PSType="system.datetime" />
              <MinValueQuery>
                <CmdletParameterMetadata PSName="BeforeInstallDate" />
              </MinValueQuery>
              <MaxValueQuery>
                <CmdletParameterMetadata PSName="AfterInstallDate" />
              </MaxValueQuery>
            </Property>
            <Property PropertyName="Name">
              <Type PSType="system.string" />
              <RegularQuery AllowGlobbing="true">
                <CmdletParameterMetadata IsMandatory="false" />
              </RegularQuery>
            </Property>
            <Property PropertyName="Status">
              <Type PSType="switch" />
              <RegularQuery AllowGlobbing="false">
                <CmdletParameterMetadata IsMandatory="false" />
              </RegularQuery>
            </Property>
            <Property PropertyName="SystemVariable">
              <Type PSType="switch" />
              <RegularQuery AllowGlobbing="false">
                <CmdletParameterMetadata IsMandatory="false" />
              </RegularQuery>
            </Property>
            <Property PropertyName="UserName">
              <Type PSType="system.string" />
              <RegularQuery AllowGlobbing="true">
                <CmdletParameterMetadata IsMandatory="false" />
              </RegularQuery>
            </Property>
            <Property PropertyName="VariableValue">
              <Type PSType="system.string" />
              <RegularQuery AllowGlobbing="true">
                <CmdletParameterMetadata IsMandatory="false" />
              </RegularQuery>
            </Property>
          </QueryableProperties>
        </GetCmdletParameters>
      </GetCmdlet>
      <!--defining additional cmdlets that modifies instance properties-->
      <!--Set-Environment: modifying instance properties-->
      <Cmdlet>
        <!--defining the ConfirmImpact which indicates how severe the changes are that this cmdlet performs-->
        <CmdletMetadata Verb="Set" ConfirmImpact="Low" />
        <!--using internal method to modify instance:-->
        <Method MethodName="cim:ModifyInstance">
          <!--defining the parameters of this cmdlet:-->
          <Parameters>
            <Parameter ParameterName="VariableValue">
              <!--the underlying parameter type is string which corresponds to the PowerShell .NET type [system.string]-->
              <Type PSType="system.string" />
              <CmdletParameterMetadata IsMandatory="false">
                <ValidateNotNull />
                <ValidateNotNullOrEmpty />
              </CmdletParameterMetadata>
            </Parameter>
          </Parameters>
        </Method>
      </Cmdlet>
      <!--Remove-Environment: invoking method cim:DeleteInstance():-->
      <Cmdlet>
        <!--defining the ConfirmImpact which indicates how severe the changes are that this cmdlet performs-->
        <CmdletMetadata Verb="Remove" Noun="WmiEnvironment" ConfirmImpact="Medium" />
        <!--defining the WMI instance method used by this cmdlet:-->
        <Method MethodName="cim:DeleteInstance">
          <ReturnValue>
            <Type PSType="system.uint32" />
            <CmdletOutputMetadata>
              <ErrorCode />
            </CmdletOutputMetadata>
          </ReturnValue>
        </Method>
      </Cmdlet>
    </InstanceCmdlets>
    <!--define the cmdlets that work with class instances.-->
    <StaticCmdlets>
      <!--New-Environment: invoking method cim:CreateInstance():-->
      <Cmdlet>
        <!--defining the ConfirmImpact which indicates how severe the changes are that this cmdlet performs-->
        <CmdletMetadata Verb="New" Noun="WmiEnvironment" ConfirmImpact="Low" />
        <!--defining the WMI instance method used by this cmdlet:-->
        <Method MethodName="cim:CreateInstance">
          <ReturnValue>
            <Type PSType="system.uint32" />
            <CmdletOutputMetadata>
              <ErrorCode />
            </CmdletOutputMetadata>
          </ReturnValue>
          <!--defining the parameters of this cmdlet:-->
          <Parameters>
            <!--native parameter name is 'Name'-->
            <Parameter ParameterName="Name">
              <!--the underlying parameter type is string which corresponds to the PowerShell .NET type [system.string]-->
              <Type PSType="system.string" />
              <CmdletParameterMetadata Position="0" IsMandatory="false">
                <ValidateNotNull />
                <ValidateNotNullOrEmpty />
              </CmdletParameterMetadata>
            </Parameter>
            <!--native parameter name is 'UserName'-->
            <Parameter ParameterName="UserName">
              <!--the underlying parameter type is string which corresponds to the PowerShell .NET type [system.string]-->
              <Type PSType="system.string" />
              <CmdletParameterMetadata Position="1" IsMandatory="false">
                <ValidateNotNull />
                <ValidateNotNullOrEmpty />
              </CmdletParameterMetadata>
            </Parameter>
            <!--native parameter name is 'VariableValue'-->
            <Parameter ParameterName="VariableValue">
              <!--the underlying parameter type is string which corresponds to the PowerShell .NET type [system.string]-->
              <Type PSType="system.string" />
              <CmdletParameterMetadata Position="2" IsMandatory="false">
                <ValidateNotNull />
                <ValidateNotNullOrEmpty />
              </CmdletParameterMetadata>
            </Parameter>
          </Parameters>
        </Method>
      </Cmdlet>
    </StaticCmdlets>
  </Class>
</PowerShellMetadata>
'@ | Set-Content -LiteralPath $cdxmlPath -Encoding UTF8

# import module
Import-Module -Name $cdxmlPath -Force -Verbose

# list new cmdlets
Get-Command -Module "Win32_Environment"

See Also

Associated Classes:

Win32_ComputerSystem

Requirements

To use Win32_Environment, the following requirements apply:

PowerShell

Get-CimInstance was introduced with PowerShell Version 3.0, which in turn was introduced on clients with Windows 8 and on servers with Windows Server 2012.

If necessary, update Windows PowerShell to Windows PowerShell 5.1, or install PowerShell 7 side-by-side.

Operating System

Win32_Environment was introduced on clients with Windows Vista and on servers with Windows Server 2008.

Namespace

Win32_Environment lives in the namespace root/cimv2. This is the default namespace. There is no need to use the -Namespace parameter in Get-CimInstance.

Implementation

Win32_Environment is implemented in CIMWin32.dll and defined in CIMWin32.mof. Both files are located in the folder C:\Windows\system32\wbem:

explorer $env:windir\system32\wbem
notepad $env:windir\system32\wbem\CIMWin32.mof