Работа с переменной среды окружения PATH

Работа с переменной среды окружения PATH

Переменная Path является переменной среды окружения, при помощи которой ОС #Windows находит нужные приложения в терминале. Рассмотрим способы редактирования значений этой переменной.

Проще говоря, в переменную Path можно добавлять пути к директориям приложений, для того чтобы при работе в терминале не прописывать полные пути к исполняемым файлам этих приложений. Например, в терминале, чтобы вызвать #Git и зафиксировать изменения нужно ввести C:\Apps\Git\git.exe commit -m 'bla-bla'. Но если добавить значение C:\Apps\Git в переменную Path, то в терминале можно просто писать git.exe commit -m 'bla-bla', больше не нужно указывать полный путь к Git’у.

Уровни переменной Path

Существует два уровня переменной Path:

  • Системный - является глобальным и его значения доступны для каждого аккаунта пользователя.
  • Пользовательский - работает в контексте конкретного аккаунта и содержит значения только этого пользователя. Под другим аккаунтом, переменная на пользовательском уровне может содержать другие значения.

В пределах аккаунта пользователя эти два уровня переменной Path объединяют свои значения.

Добавление значений в переменную Path

Добавить свои значения в переменную Path можно несколькими способами:

  • Графический интерфейс ОС.
  • Команда в CMD при помощи утилиты setx.
  • Команда в PowerShell.

Значения в переменной Path разделяются символом ;.

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

Командная строка CMD

Управление переменными среды окружения в #CMD происходит при помощи утилиты setx.

Системный уровень

Чтобы добавить свои значения в переменную Path на системном уровне, необходимо указать ключ /m:

1
setx /m Path "%Path%C:\Apps\App_01;C:\Apps\App_02"

Необходимости в скрипте, который добавляет значения в переменную Path на системном уровне, нет. Но я всё же его написал, пусть будет.

cmd.set.env.path.system.bat
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
rem Setting PATH variable for system.
rem
rem @package   CMD
rem @author    Kai Kimera <mail@kai.kim>
rem @copyright 2023 Library Online
rem @license   MIT
rem @version   0.1.0
rem @link      https://lib.onl/ru/articles/2023/10/1f062637-3227-56d7-93e3-126d1c80f5a8/
rem ------------------------------------------------------------------------------------------------------------------ ::

@echo off
setLocal EnableDelayedExpansion

rem Custom PATH.
set "pathArray=C:\Apps\App_01 C:\Apps\App_02 C:\Apps\App_03"

rem Building a system PATH variable.
for %%p in ( %pathArray% ) do ( set "pathCustom=%%p;!pathCustom!" )

rem Setting a new PATH variable.
setx /m Path "%Path%!pathCustom!"

В переменной pathArray указывается массив из путей, которые необходимо добавить в Path на системном уровне.

Пользовательский уровень

Добавить свои значения в переменную Path на пользовательском уровне:

1
setx Path "%Path%C:\Apps\App_01;C:\Apps\App_02"

Но есть одна особенность: так как переменная Path объединяет значения системного и пользовательского уровней, то при такой команде, утилита setx пропишет в Path пользовательского уровня все значения из системного. Таким образом, получится дублирование содержимого Path системного уровня в пользовательском. Это не критично, но можно сделать более элегантно…

Для того, чтобы обойти вышеуказанную особенность, необходимо написать скрипт, который будет при вызове переменной Path вырезать из неё значения системного уровня. Собственно, скрипт я написал.

cmd.set.env.path.user.bat
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
rem Setting PATH variable for user.
rem
rem @package   CMD
rem @author    Kai Kimera <mail@kai.kim>
rem @copyright 2023 Library Online
rem @license   MIT
rem @version   0.1.0
rem @link      https://lib.onl/ru/articles/2023/10/1f062637-3227-56d7-93e3-126d1c80f5a8/
rem ------------------------------------------------------------------------------------------------------------------ ::

@echo off
setLocal EnableDelayedExpansion

rem Custom PATH.
set "pathArray=C:\Apps\App_01 C:\Apps\App_02 C:\Apps\App_03"

rem Getting the current PATH variable.
for /f "tokens=2,*" %%a in ( 'reg query HKCU\Environment /v Path' ) do ( set "pathUser=%%b" )

rem Building a user PATH variable.
for %%p in ( %pathArray% ) do ( set "pathCustom=%%p;!pathCustom!" )

rem Setting a new PATH variable.
setx Path "!pathUser!!pathCustom!"

В переменной pathArray указывается массив из путей, которые необходимо добавить в Path на пользовательском уровне. При этом, добавление значений из системного уровня не произойдёт. Наша переменная Path пользовательского уровня останется чистенькой и красивой.

Терминал PowerShell

В #PowerShell для управления переменными окружения существуют методы:

  • [Environment]::GetEnvironmentVariables() - получение значения переменной среды окружения.
  • [Environment]::SetEnvironmentVariable() - установка значения переменной среды окружения.

Системный уровень

Для добавления значений в переменную Path на системном уровне, я написал небольшой скрипт.

pwsh.set.env.path.system.ps1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<#PSScriptInfo
  .VERSION      0.1.0
  .GUID         41643d28-3808-4a6f-a322-d87ed4384d5f
  .AUTHOR       Kai Kimera
  .AUTHOREMAIL  mail@kai.kim
  .COMPANYNAME  Library Online
  .COPYRIGHT    2023 Library Online. All rights reserved.
  .LICENSEURI   https://choosealicense.com/licenses/mit/
  .PROJECTURI   https://lib.onl/ru/articles/2023/10/1f062637-3227-56d7-93e3-126d1c80f5a8/
#>

#Requires -Version 7.2
#Requires -RunAsAdministrator

<#
  .SYNOPSIS
  Setting PATH variable for system.

  .DESCRIPTION
  The script configures the PATH variable values for the system.

  .EXAMPLE
  .\pwsh.set.env.path.system.ps1 -P 'C:\Apps\App_01', 'C:\Apps\App_02', 'C:\Apps\App_03'

  .LINK
  https://lib.onl/ru/articles/2023/10/1f062637-3227-56d7-93e3-126d1c80f5a8/
#>

Param(
  [Alias('P')][string[]]$Path
)

function Set-EnvPathSystem() {
  $Path | ForEach-Object {
    [Environment]::SetEnvironmentVariable(
      'Path', ([Environment]::GetEnvironmentVariables('Machine')).Path + "${_}" + [IO.Path]::PathSeparator, 'Machine'
    )
  }
}

Set-EnvPathSystem

Вызов скрипта осуществляется следующим образом:

Терминал
1
.\pwsh.set.env.path.system.ps1 -P 'C:\Apps\App_01', 'C:\Apps\App_02', 'C:\Apps\App_03'

В параметре -P указываются значения, которые необходимо добавить в переменную Path системного уровня.

Пользовательский уровень

А здесь скрипт, который отвечает за добавление в переменную Path значений на пользовательском уровне.

pwsh.set.env.path.user.ps1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<#PSScriptInfo
  .VERSION      0.1.0
  .GUID         79f23918-308a-412c-8835-b1bb9c9193e3
  .AUTHOR       Kai Kimera
  .AUTHOREMAIL  mail@kai.kim
  .COMPANYNAME  Library Online
  .COPYRIGHT    2023 Library Online. All rights reserved.
  .LICENSEURI   https://choosealicense.com/licenses/mit/
  .PROJECTURI   https://lib.onl/ru/articles/2023/10/1f062637-3227-56d7-93e3-126d1c80f5a8/
#>

#Requires -Version 7.2

<#
  .SYNOPSIS
  Setting PATH variable for user.

  .DESCRIPTION
  The script configures the PATH variable values for the user.

  .EXAMPLE
  .\pwsh.set.env.path.user.ps1 -P 'C:\Apps\App_01', 'C:\Apps\App_02', 'C:\Apps\App_03'

  .LINK
  https://lib.onl/ru/articles/2023/10/1f062637-3227-56d7-93e3-126d1c80f5a8/
#>

Param(
  [Alias('P')][string[]]$Path
)

function Set-EnvPathUser() {
  $Path | ForEach-Object {
    [Environment]::SetEnvironmentVariable(
      'Path', ([Environment]::GetEnvironmentVariables('User')).Path + "${_}" + [IO.Path]::PathSeparator, 'User'
    )
  }
}

Set-EnvPathUser

Вызов скрипта осуществляется следующим образом:

Терминал
1
.\pwsh.set.env.path.user.ps1 -P 'C:\Apps\App_01', 'C:\Apps\App_02', 'C:\Apps\App_03'

В параметре -P указываются значения, которые необходимо добавить в переменную Path пользовательского уровня.

Общий скрипт

Не знаю, почему я сразу не написал общий скрипт для всех уровней… Решил под завершение статьи реализовать подобную штуку.

pwsh.set.env.path.ps1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<#PSScriptInfo
  .VERSION      0.1.0
  .GUID         14efdc7d-1edd-4b40-b6d2-623288ce1659
  .AUTHOR       Kai Kimera
  .AUTHOREMAIL  mail@kai.kim
  .COMPANYNAME  Library Online
  .COPYRIGHT    2023 Library Online. All rights reserved.
  .LICENSEURI   https://choosealicense.com/licenses/mit/
  .PROJECTURI   https://lib.onl/ru/articles/2023/10/1f062637-3227-56d7-93e3-126d1c80f5a8/
#>

#Requires -Version 7.2

<#
  .SYNOPSIS
  Setting the PATH variable.

  .DESCRIPTION
  The script configures the PATH variable values.

  .EXAMPLE
  .\pwsh.set.env.path.ps1 -P 'C:\Apps\App_01', 'C:\Apps\App_02', 'C:\Apps\App_03' -T 'Machine'

  .EXAMPLE
  .\pwsh.set.env.path.ps1 -P 'C:\Apps\App_01', 'C:\Apps\App_02', 'C:\Apps\App_03' -T 'User'

  .LINK
  https://lib.onl/ru/articles/2023/10/1f062637-3227-56d7-93e3-126d1c80f5a8/
#>


Param(
  [Alias('P')][string[]]$Path,
  [Parameter(Mandatory)][ValidateSet('Machine', 'User')][Alias('T')][string[]]$Target
)

function Set-EnvPath() {
  $Path | ForEach-Object {
    [Environment]::SetEnvironmentVariable(
      'Path', ([Environment]::GetEnvironmentVariables("${Target}")).Path + "${_}" + [IO.Path]::PathSeparator, "${Target}"
    )
  }
}

Set-EnvPath

Вызывается скрипт обычным способом:

Терминал
1
.\pwsh.set.env.path.ps1 -P 'C:\Apps\App_01', 'C:\Apps\App_02', 'C:\Apps\App_03' -T 'User'

Но отличается от выше приведённых скриптов дополнительным параметром -T, который указывает уровень переменной Path и может принимать следующие значения:

  • Machine - для системного уровня.
  • User - для пользовательского уровня.