reg query and batch file for loop tricks that refreshes the cmd environment from the registry settings: choco/RefreshEnv.cmd at master · chocolatey/choco · GitHub
Posted by jpluimers on 2021/03/04
I bumped into a very interesting [WayBack] choco/RefreshEnv.cmd at master · chocolatey/choco · GitHub.
It allows you to refresh your cmd environment from new settings that were only applied to the registry using the SET
command.
Note there is a PowerShell counterpart too: [WayBack] choco/Update-SessionEnvironment.ps1 at master · chocolatey/choco · GitHub
There are many cool tricks in it, most of which you can see in the [WayBack] new commit history, and a few you can find back in the [WayBack] old commit history of the previous repository (I have no idea why those histories have never been merged).
Intermediate batch files
The basic structure is to first create some intermediate batch files, then delete them afterwards:
"%TEMP%\_envget.tmp"
- is used in
:GetRegEnv
to get all environment variables for the MACHINE or USER level, then loop through them and call:SetFromReg
during each iteration (except for thePath
environment variable which is skipped).
- is used in
"%TEMP%\_envset.tmp"
- is used in
:SetFromReg
to emit one line ofSET
code to"%TEMP%\_env.cmd"
.
- is used in
"%TEMP%\_env.cmd"
- Contains the
SET
commands for the new environment variable values.
- Contains the
All the above methods use quoting to ensure that environment variables having names or values containing spaces are handled correctly.
Echo without newline
I like the echo | set /p
trick to echo
a string without a newline allows it to start as this:
C:\>RefreshEnv
Refreshing environment variables from registry for cmd.exe. Please wait...
then finish like this by appending another string to it:
C:\>RefreshEnv
Refreshing environment variables from registry for cmd.exe. Please wait...Finished..
It is explained in the old history at [WayBack] (GH-153)(GH-134) Update PATH on cmd.exe · chocolatey/chocolatey@a09e158 · GitHub.
There is an even more interesting example of this trick in [WayBack] windows – What does /p mean in set /p? – Stack Overflow:
<nul set /p=This will not generate a new line
Spaces, what spaces
One hard thing in scripting is taking into account that path names can contain spaces. This means you need to carefully quote path names, but not overdo the quotes, otherwise the quoting works against you.
Two commits from the commit history show there were two weak spots that had to be changed in [WayBack] (GH-1227) Fix: RefreshEnv doesn’t set path w/spaces · chocolatey/choco@fdfcd06 · GitHub.
The environment has a MACHINE and USER part
Environment variables can come from two places in the registry:
HKLM\System\CurrentControlSet\Control\Session Manager\Environment
HKCU\Environment
Normally, the second overrides the first.
This means they are grabbed from the registry MACHINE and USER order, then applied to the cmd environment.
Special case PATH
The PATH environment variable is special for two reasons:
- In the registry it is called
Path
, but in the environment it is usually calledPATH
(this is true for both the MACHINE and USER parts of the registry). New values are applied with thePath
environment variable name, so after executingRefreshEnv
once, they are calledPath
in the cmd.exe environment too. - PATH is a combination from two PATH entries in the registry in the MACHINE and USER level, so it needs to be combined as you can see in [WayBack] choco/RefreshEnv.cmd at master · chocolatey/choco · GitHub.:
:: Caution: do not insert space-chars before >> redirection sign echo/set "Path=%%Path_HKLM%%;%%Path_HKCU%%" >> "%TEMP%\_env.cmd"
I am not sure why there is a space before the >>
, given there is a comment above it there should not be one.
The SET command however, puts the MACHINE PATH
in front of the USER PATH
.
Special case USERNAME
, and collateral PROCESSOR_ARCHITECTURE
The USERNAME
environment variable special too. In the registry, it is only in the MACHINE part, but with a value SYSTEM
.
In cmd.exe, it is actually filled with the current username, so it should not be overwritten with the one in the MACHINE part.
Currently this is resolved by storing a copy of the old value of USERNAME
and PROCESSOR_ARCHITECTURE
in [WayBack] (GH-902) Fix: User changed to SYSTEM during env update · chocolatey/choco@cb6b92c · GitHub.
I am not sure why PROCESSOR_ARCHITECTURE
is also stores.
In any case, this means that setting a USERNAME
or PROCESSOR_ARCHITECTURE
in the USER part of the registry, will not be reflected by RefreshEnv
.
I am not sure yet when that can cause problems, so this is a reminder to myself that if ever it does, then this logic needs to be changed.
–jeroen
Leave a comment