Как я могу использовать .bat файл для удаления определенных токенов из переменной среды PATH?

Я пишу деинсталляцию script, поэтому я хотел бы "отменить" изменения, внесенные в систему. Для достижения этой цели я хотел бы проанализировать переменную PATH и удалить любые значения, добавленные в установку PATH.


Для этого я разработал следующий псевдокод -

  • Сохраните содержимое PATH во временную переменную
  • Разделите PATH на токены, используя символ ; в качестве разделителя и пропустите каждый токен
  • (In Loop) Определите, является ли текущий токен добавленным установкой
  • (In Loop) Если текущий токен не был добавлен установкой, сохраните его для добавления в обновленный PATH (во временной переменной)
  • Сохранить обновленный PATH

Я ожидал, что это будет относительно просто реализовать.


Первый шаг, сохранение PATH прост.

SET TEMP_PATH=%PATH% 

Однако, когда я пытаюсь пропустить каждый токен, он не будет работать так, как я ожидал.

FOR /F "delims=;" %%A IN (%TEMP_PATH%) DO ECHO %%A 

Эта команда выводит только первый токен, и последующие маркеры не повторяются.


Итак, у меня есть два вопроса -

  • Как я могу пропустить неизвестное количество токенов и работать с каждым из них?
  • Есть ли другой способ достичь той же цели, которая может быть проще?

Спасибо.

Ответ 1

Приведенный ниже пакетный код удаляет 1 или несколько путей к папкам, как определено в верхней части скрипта с помощью PathToRemove1, PathToRemove2,... из

  • пользователь PATH текущей учетной записи пользователя, хранящийся в реестре Windows под ключом
    HKEY_CURRENT_USER\Environment
  • система PATH хранится в реестре Windows под ключом
    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment

Обновление системы PATH требует привилегий администратора, что означает, что пакетный файл должен выполняться от имени администратора, если контроль учетных записей пользователей (UAC) не отключен для учетной записи пользователя, выполняющей пакетный файл.

Пакетный код работает только для Windows Vista и более поздних версий Windows, поскольку команда SETX по умолчанию недоступна в Windows XP или даже в предыдущих версиях Windows.

Доступность команды SETX приведена в статье SS64 о документации SetX и Microsoft SetX.

Различия в выходных данных reg.exe в Windows XP по сравнению с более поздними версиями Windows см. в статье Роба ван дер Вуде Чтение реестра NT с помощью REG Query. Различные выходные данные reg.exe учитываются в приведенном ниже коде партии.

Для объяснения, почему не использовать локальный PATH, как определено в настоящее время при выполнении командного файла, прочитайте вопросы, ответы и комментарии

Комментированный пакетный код для удаления пути к папке от пользователя и системы PATH:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "PathToRemove1=C:\Temp\Test"
set "PathToRemove2=C:\Temp"

rem Get directly from Windows registry the system PATH variable value.
for /F "skip=2 tokens=1,2*" %%N in ('%SystemRoot%\System32\reg.exe query "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /v "Path" 2^>nul') do (
    if /I "%%N" == "Path" (
        set "SystemPath=%%P"
        if defined SystemPath goto CheckSystemPath
    )
)
echo Error: System environment variable PATH not found with a value in Windows registry.
echo/
goto UserPath

:CheckSystemPath
setlocal EnableDelayedExpansion
rem Does the system PATH not end with a semicolon, append one temporarily.
if not "!SystemPath:~-1!" == ";" set "SystemPath=!SystemPath!;"
rem System PATH should contain only backslashes and not slashes.
set "SystemPath=!SystemPath:/=\!"

rem Check case-insensitive for the folder paths to remove as defined at top
rem of this batch script and remove them if indeed found in system PATH.
set "PathModified=0"
for /F "tokens=1* delims==" %%I in ('set PathToRemove') do (
    if not "!SystemPath:%%J;=!" == "!SystemPath!" (
        set "SystemPath=!SystemPath:%%J;=!"
        set "PathModified=1"
    )
)

rem Replace all two or more ; in series by just one ; in system path.
:CleanSystem
if not "!SystemPath:;;=;!" == "!SystemPath!" set "SystemPath=!SystemPath:;;=;!" & goto CleanSystem

rem Remove the semicolon at end of system PATH if there is one.
if "!SystemPath:~-1!" == ";" set "SystemPath=!SystemPath:~0,-1!"
rem Remove a backslash at end of system PATH if there is one.
if "!SystemPath:~-1!" == "\" set "SystemPath=!SystemPath:~0,-1!"

rem Update system PATH using command SETX which requires administrator
rem privileges if the system PATH needs to be modified at all. SETX is
rem by default not installed on Windows XP and truncates string values
rem longer than 1024 characters to 1024 characters. So use alternatively
rem command REG to add system PATH if command SETX cannot be used or is
rem not available at all.
if "%PathModified%" == "1" (
    set "UseSetx=1"
    if not "!SystemPath:~1024,1!" == "" set "UseSetx="
    if not exist %SystemRoot%\System32\setx.exe set "UseSetx="
    if defined UseSetx (
        %SystemRoot%\System32\setx.exe Path "!SystemPath!" /M >nul
    ) else (
        set "ValueType=REG_EXPAND_SZ"
        if "!SystemPath:%%=!" == "!SystemPath!" set "ValueType=REG_SZ"
        %SystemRoot%\System32\reg.exe ADD "HKLM\System\CurrentControlSet\Control\Session Manager\Environment" /f /v Path /t !ValueType! /d "!SystemPath!" >nul
    )
)
endlocal

:UserPath
rem Get directly from Windows registry the user PATH variable value.
for /F "skip=2 tokens=1,2*" %%N in ('%SystemRoot%\System32\reg.exe query "HKCU\Environment" /v "Path" 2^>nul') do (
    if /I "%%N" == "Path" (
        set "UserPath=%%P"
        if defined UserPath goto CheckUserPath
        rem User PATH exists, but with no value, delete user PATH.
        goto DeleteUserPath
    )
)
rem This PATH variable does often not exist and therefore nothing to do here.
goto PathUpdateDone

:CheckUserPath
setlocal EnableDelayedExpansion
rem Does the user PATH not end with a semicolon, append one temporarily.
if not "!UserPath:~-1!" == ";" set "UserPath=!UserPath!;"

rem Check case-insensitive for the folder paths to remove as defined at top
rem of this batch script and remove them if indeed found in user PATH.
set "PathModified=0"
for /F "tokens=1* delims==" %%I in ('set PathToRemove') do (
    if not "!UserPath:%%J;=!" == "!UserPath!" (
        set "UserPath=!UserPath:%%J;=!"
        set "PathModified=1"
        if not defined UserPath goto DeleteUserPath
    )
)

rem Replace all two or more ; in series by just one ; in user path.
:CleanUser
if not "!UserPath:;;=;!" == "!UserPath!" set "UserPath=!UserPath:;;=;!" & goto CleanUser

rem Remove the semicolon at end of user PATH if there is one.
if "!UserPath:~-1!" == ";" set "UserPath=!UserPath:~0,-1!"
if not defined UserPath goto DeleteUserPath

rem Update user PATH using command SETX which does not require administrator
rem privileges if the user PATH needs to be modified at all. SETX is
rem by default not installed on Windows XP and truncates string values
rem longer than 1024 characters to 1024 characters. So use alternatively
rem command REG to add user PATH if command SETX cannot be used or is
rem not available at all.
if "%PathModified%" == "1" (
    set "UseSetx=1"
    if not "!UserPath:~1024,1!" == "" set "UseSetx="
    if not exist %SystemRoot%\System32\setx.exe set "UseSetx="
    if defined UseSetx (
        %SystemRoot%\System32\setx.exe Path "!UserPath!" /M >nul
    ) else (
        set "ValueType=REG_EXPAND_SZ"
        if "!UserPath:%%=!" == "!UserPath!" set "ValueType=REG_SZ"
        %SystemRoot%\System32\reg.exe ADD "HKCU\Environment" /f /v Path /t !ValueType! /d "!UserPath!" >nul
    )
)
goto PathUpdateDone

:DeleteUserPath
rem Delete the user PATH as it contains only folder paths to remove.
%SystemRoot%\System32\reg.exe delete "HKCU\Environment" /v "Path" /f >nul

:PathUpdateDone
rem Other code could be inserted here.
endlocal
endlocal

Приведенный выше пакетный код использует простую подстановку строк без учета регистра и сравнение строк с учетом регистра, чтобы проверить, присутствует ли текущий путь для удаления в пользовательском или системном PATH. Это работает, только если хорошо известно, как пути к папкам были добавлены ранее, и пользователь не изменил их за это время. Более безопасный способ проверки, содержит ли PATH путь к папке, см. в ответе на вопрос Как проверить, существует ли каталог в% PATH%?, написанный dbenham.

Внимание: Этот пакетный код не предназначен для обработки очень редких случаев использования системным или пользователем PATH пути к папке с одной или несколькими точками с запятой в закрытой строке пути в двойных кавычках, чтобы получить ;, интерпретируемый Windows внутри строки пути к двойным кавычкам как буквенный символ вместо разделителя между путями к папкам.

Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и внимательно прочитайте все страницы справки, отображаемые для каждой команды.

  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • reg /?
  • reg add /?
  • reg delete /?
  • reg query /?
  • rem /?
  • set /?
  • setlocal /?
  • setx /?

См. также статью Microsoft о использовании операторов перенаправления команд для объяснения >nul и 2>nul с оператором перенаправления >, экранированным с ^, чтобы использовать перенаправление при выполнении reg.exe вместо интерпретация 2>nul неуместна для команды FOR, которая приведет к завершению пакетной обработки интерпретатором команд Windows из-за синтаксической ошибки.

Ответ 2

Эта команда выводит только первый токен, и последующие маркеры не повторяются.

FOR /F "delims=;" %%A IN (%TEMP_PATH%) DO ECHO %%A 

Как я могу пропустить неизвестное количество токенов и работать с каждым из них?

Используйте следующий командный файл.

SplitPath.cmd

@echo off
setlocal
for %%a in ("%path:;=";"%") do (
  echo %%~a
  )
endlocal

Результат:

F:\test>path
PATH=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\apps\WSCC\Sysinternals Suite;C:\apps\WSCC\NirSoft Utilities

F:\test>splitpath
C:\Windows\system32
C:\Windows
C:\Windows\System32\Wbem
C:\Windows\System32\WindowsPowerShell\v1.0\
C:\apps\WSCC\Sysinternals Suite
C:\apps\WSCC\NirSoft Utilities

Примечания:

  • Измените цикл for, если это необходимо, чтобы реализовать остальную часть вашего псевдокода.

Дополнительная литература