How do I set a Machine environment variable from a Chocolatey package?
chocolatey, environment-variables, escaping, powershell
Solution
Why not use the built in helper for this, `Install-ChocolateyEnvironmentVariable`. The usage is quite simple...
Install-ChocolateyEnvironmentVariable 'JAVA_HOME' 'path\to\jre' 'Machine'
Problem
I'm the author of several Chocolatey packages that need to set environment variables as part of the proper "installation" of the package. For example: `ANT_HOME`, `MW_HOME`, and `JAVA_HOME` in the Java ecosystem should point to the installation directory for ant, weblogic, and java, respectively. And, since Chocolatey is a machine-wide package manager, my thought would be to set these machine-wide (MSDN). ``` [System.Environment]::SetEnvironmentVariable("JAVA_HOME", "path/to/jre/install", "Machine") ``` If I just run that, I get the expected permission exception Exception calling "SetEnvironmentVariable" with "3" argument(s): "Requested registry access is not allowed." If I run the same command in an elevated prompt, manually, everything works fine. So, I need to invoke it in an elevated prompt. With Chocolatey, you're supposed to use: `[Start-ChocolateyProcessAsAdmin][2]` like so ``` Start-ChocolateyProcessAsAdmin @" [System.Environment]::SetEnvironmentVariable("JAVA_HOME", "path/to/jre/install", "Machine") "@ ``` It prompts for elevation (I always run in a normal prompt when developing to be sure that it's actually working), but I see red errors flash by and this message with no warning/error Elevating Permissions and running C:\windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy unrestricted -Command "& import-module -name 'C:\Chocolatey\chocolateyinstall\helpers\chocolateyInstaller.psm1'; try{[System.Environment]::SetEnvironmentVariable("JAVA_HOME", "path/to/jre/install", "Machine"); start-sleep 6;}catch{write-error 'That was not sucessful';start-sleep 8;throw;}". This may take awhile, depending on the statements. What gives? UPDATE: Some combination of the following makes it work, mysteriously... adding line-terminators (even to single statements) and wrapping all the arguments in single quotes. ``` Start-ChocolateyProcessAsAdmin @" [System.Environment]::SetEnvironmentVariable('JAVA_HOME', 'path/to/jre/install', 'Machine'); "@ ``` I would still like a non-brute-force answer. I'm sure it's a combination of PowerShell's nightmare string quoting/interpreting rules + Chocolatey's invocation. UPDATE: I'm also having trouble with multiple statements, even though I'm separating them! ``` Start-ChocolateyProcessAsAdmin @" [System.Environment]::SetEnvironmentVariable('MW_HOME', 'path/to/wl/install', 'Machine'); [System.Environment]::SetEnvironmentVariable('WL_HOME', 'path/to/wl/install/wlserver', 'Machine'); "@ ``` I saw, but did not capture, a Chocolatey log statement on screen that showed one of the line-terminators removed! THOUGHT: I mean, should I just not do this and write an easy "User" environment variable instead? It's not correct! The damn things are installed machine-wide... I don't want to give up yet.