Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get only the user path variable?

Tags:

batch-file

Echo %PATH% returns system PATH variable + user PATH variable.

How to get only the user PATH variable?

like image 374
Snap Aoe Avatar asked May 12 '17 09:05

Snap Aoe


1 Answers

The system PATH variable is stored in Windows registry with value Path of type REG_EXPAND_SZ containing references to environment variables like %SystemRoot% or if not correct modified by an application of type REG_SZ without environment variable references under the registry key:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment

The user PATH variable does not exist by default in Windows registry. It is stored in Windows registry with value Path of type REG_EXPAND_SZ or REG_SZ once created by an application or manually by the user under the registry key:

HKEY_CURRENT_USER\Environment

The external command REG with command QUERY can be used to read the value of the system or the user PATH variable directly from Windows registry with standard user permissions.

It is possible to read the user PATH variable from Windows registry and assign its value to an environment variable UserPath with additionally expanding all environment variables in directory paths list.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "UserPath="
for /F "skip=2 tokens=1,2*" %%G in ('%SystemRoot%\System32\reg.exe query "HKCU\Environment" /v "Path" 2^>nul') do if /I "%%G" == "Path" (
    if /I "%%H" == "REG_EXPAND_SZ" (call set "UserPath=%%I") else if /I "%%H" == "REG_SZ" set "UserPath=%%I"
    if defined UserPath goto UserPathRead
)
echo User PATH is not defined or has no string value.
goto EndBatch

:UserPathRead
setlocal EnableDelayedExpansion
echo The user PATH is: !UserPath!
endlocal

:EndBatch
echo/
pause
endlocal

The output format of reg query depends on version of Windows which makes the additional case-insensitive IF condition necessary. For details on reg query output format see for example Reading NT's Registry with REG Query written by Rob van der Woude.

Example output of reg query HKCU\Environment /v Path on Windows XP:


! REG.EXE VERSION 3.0

HKEY_CURRENT_USER\Environment
    Path        REG_SZ  C:\BatUtils

There is an empty line at beginning and one more at end of the output as well as a header line and one more empty line above the line with the registry key.

The line with the data of interest starts with four space characters and has next the case-insensitive name of the registry value Path. Then a single horizontal tab character is output left to the registry value type REG_SZ. Last there is one more horizontal tab character before the string value of Path is output which could contain also one or more space characters.

Example output of reg query HKCU\Environment /v Path on Windows Vista or newer Windows versions:


HKEY_CURRENT_USER\Environment
    Path    REG_SZ    C:\BatUtils

There is also an empty line at beginning and one more at end of the output. But there is no header. The second line contains already the registry key.

The line with the data of interest starts with four space characters and has next the case-insensitive name of the registry value Path. Then four spaces instead of a tab are output left to the registry value type REG_SZ. Last there are again four spaces instead of a tab before the string value of Path is output which could contain also one or more space characters.

The command REG is executed in a separate command process in background by FOR. The error message output by REG to handle STDERR in case of registry key HKCU\Environment or value Path do not exist is suppressed by redirecting it to device NUL with 2>nul. The redirection operator > must be escaped here with caret character ^ to be interpreted as literal character on parsing FOR command line by Windows command interpreter, but as redirection operator on later execution of REG command line in separate background command process.

The FOR options defined with "skip=2 tokens=1,2*" result in skipping the first two lines of REG output and splitting the other lines up into three substrings (tokens) using the default delimiters space and tab.

The first space/tab delimited string is assigned to first loop variable G which is the name of the variable on reaching the line with the data of interest.

The second substring being the registry value type is assigned to loop variable H being the next character in ASCII table. This behavior is the reason why FOR loop variables are case-sensitive.

Everything after spaces/tabs after second substring is assigned to loop variable I without splitting up the rest of the line because of * in options string after tokens=1,2.

So on Windows Vista and later Windows versions the command FOR processes as first line from output of REG the line with Path while on Windows XP the first line processed is the line with the registry key which is the reason why the first IF condition is necessary.

The second IF condition makes a case-insensitive string comparison to find out the type of the registry value with name Path. The string assigned to Path contains on type REG_EXPAND_SZ one or more environment variable references. For that reason the command call is used which results in parsing the string value read from the registry and assigned to the loop variable I by the Windows command processor to expand all environment variable references before command SET is executed to assign the expanded string value to environment variable UserPath.

Note: cmd.exe searches for an executable or script with name set using the local environment variables PATHEXT and PATH because of the usage of command CALL. The command CALL is designed for calling a batch file from within a batch file and not to force the Windows command processor to parse a command line a second time.

The third IF condition is executed only if the registry value Path is not of type REG_EXPAND_SZ. It compares case-insensitive the registry value type against the string REG_SZ in which case the string value of Path can be assigned directly to the environment variable UserPath.

The environment variable UserPath is explicitly undefined above the FOR loop. So if the current line has as first string Path in any case and the registry value type is REG_EXPAND_SZ or REG_SZ, there should be now defined the environment variable UserPath as otherwise there is either a registry value Path with wrong type or with an empty string. It is possible to have Path stored in Windows registry with an empty string, but it is not possible to define the environment variable UserPath with an empty string.

The fourth IF condition verifies that the environment variable UserPath is really defined with a non-empty string. In this case the command GOTO is used to exit the FOR loop on having successfully read the user PATH variable from Windows registry by jumping to the command block for further processing the environment variable UserPath.

The command block below the FOR loop is reached if the user PATH variable does not exist at all in Windows registry, or is of wrong type, or exists with an empty string.

For completeness a batch code to

  • read system AND user PATH from Windows registry without expansion,
  • concatenate both PATH variables to PATH with overwriting local PATH in current command process in current environment,
  • expand all environment variable references now if necessary at all.
  • replace all ;; by ; in PATH value and
  • remove ; from end of PATH value if there is one.

This batch code does not check if user PATH contains one or more directory paths being already present in system PATH before concatenating them. So it is possible that a directory path is in local PATH finally present more than once.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Get directly from Windows registry the system PATH variable value.
set "PathExpand="
set "PathSystem="
for /F "skip=2 tokens=1,2*" %%G in ('%SystemRoot%\System32\reg.exe query "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /v "Path" 2^>nul') do if /I "%%G" == "Path" (
    if /I "%%H" == "REG_EXPAND_SZ" (set "PathExpand=1" & set "PathSystem=%%I") else if /I "%%H" == "REG_SZ" set "PathSystem=%%I"
    if defined PathSystem goto GetUserPath
)

rem Get directly from Windows registry the user PATH variable value.
:GetUserPath
set "PathUser="
for /F "skip=2 tokens=1,2*" %%G in ('%SystemRoot%\System32\reg.exe query "HKCU\Environment" /v "Path" 2^>nul') do if /I "%%G" == "Path" (
    if /I "%%H" == "REG_EXPAND_SZ" (set "PathExpand=1" & set "PathUser=%%I") else if /I "%%H" == "REG_SZ" set "PathUser=%%I"
    if defined PathUser goto SetPath
)

rem Concatenate the two PATH values to a single value.
rem Expand the environment variable references if that is necessary at all.
rem Next replace all two consecutive semicolons by a single semicolon.
rem Last remove semicolon from end of the directories list if there is one.

:SetPath
set "PATH=%PathSystem%;%PathUser%"
if defined PathExpand call set "PATH=%PATH%"
set "PATH=%PATH:;;=;%"
if "%PATH:~-1%" == ";" set "PATH=%PATH:~0,-1%"

rem Output the environment variables PATH and PATHEXT and all other
rem environment variables starting case-insensitive with the string
rem Path as used in this batch file code to see what happened here.
set PATH
endlocal

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • call /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • pause /?
  • reg /?
  • reg query /?
  • rem /?
  • set /?
  • setlocal /?

Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and the answer on Stack Overflow topic Single line with multiple commands using Windows batch file for meaning of operator & on a command line.

like image 119
Mofi Avatar answered Jan 02 '23 12:01

Mofi