Home > Blockchain >  Setting User level environment variables with Chocolatey
Setting User level environment variables with Chocolatey

Time:10-06

I'm writing a Chocolately package that needs to install my program and then set a User level environment variable that the program needs.

As recommended in the documentation, I've installed Chocolatey from a PowerShell terminal with elevated privileges. In my chocolatelyinstall.ps1 script I can set the environment variable with this command:

Install-ChocolateyEnvironmentVariable -VariableName "my_env_var" -VariableValue "Wibble" -VariableType User

However, when I install the package: choco install my_package -s . the environment variable is set at User level for the administrator account, rather than the standard user account.

Installing the package in a regular (non-elevated) PowerShell process, simply fails with:

Access to the path 'C:\ProgramData\chocolatey\lib\my_package\tools' is denied.

Is there any way to set the Env var on the standard user account, rather than the admin account?

All assistance is welcome!

CodePudding user response:

Indeed (to recap), if your elevated process uses a different (of necessity administrative) user account than the current window-station user (the user that started the current OS user session), you cannot define environment variables for the windows-station user using the usual methods that target the HKEY_CURRENT_USER hive, as it reflects the elevating user's data.

  • Conversely, this means that if your window-station user is an administrator and therefore allowed to run with elevation themselves, the problem will not arise.

Workaround (takes the place of your Install-ChocolateyEnvironmentVariable call):

  • Determine the identify of the window-station user in terms of its SID (security identify).

  • Use the SID to target the window-station user's specific registry hive, under HKEY_USERS.

  • Use a dummy user-level [Environment]::SetEnvironmentVariable() call so as to broadcast a notification of the environment change (modifying the registry directly doesn't do that), notably so that the Windows (GUI) shell refreshes its environment.

# Get the window station user and split into domain name and user name.
$domain, $user = (Get-CimInstance Win32_ComputerSystem).UserName -split '\\'

# Obtain their SID.
$sid = [System.Security.Principal.NTAccount]::new(
  $domain, 
  $user
).Translate([System.Security.Principal.SecurityIdentifier]).Value

# Set an environment variable for them.
Set-ItemProperty "registry::HKEY_USERS\$sid\Environment" my_env_var Wibble

# Set and remove a dummy variable for the *current user*, 
# so as to notify the GUI shell that the environment changed.
('unused', $null).ForEach({ 
  [Environment]::SetEnvironmentVariable("_PowerShell_$PID", $_, 'User') 
})
  • Related