Windows $ env: path = "$ ($ env: path) ;." где это было добавлено? - PullRequest
1 голос
/ 20 февраля 2020

Я "исправил" проблему, запустив $env:path ="$($env:path);." из PowerShell. Видимо это добавило текущий каталог к ​​моему пути. Какую переменную пути он добавил, пожалуйста? В диалоге переменных окружения, где я могу его увидеть? Пользовательские переменные? Системные переменные?

Я в замешательстве, потому что я уже добавил папку к системным переменным path, но не смог запустить содержащийся в ней сценарий, пока не запустил `` $ env: path = "$ ($ env: path); . "

Ответы [ 3 ]

2 голосов
/ 20 февраля 2020

Обновления $env:EnvVarName влияют только на текущий процесс - постоянные изменения через реестр не вносятся:

$env:EnvVarName = 'foo'

эквивалентно вызову. NET метод System.Environment.SetEnvironmentVariable следующим образом:

[Environment]::SetEnvironmentVariable('EnvVarName', 'foo', 'Process')

То есть область действия обновления - текущий процесс .

Только если вы замените 'User' или 'Machine' на 'Process' в вышеуказанном вызове (поддерживается только Windows [1] ), вы постоянно обновите среду переменные в реестре (для текущего пользователя или локального компьютера ( всех пользователей) соответственно), для будущих сеансов (процессов) [2 ] .

Начиная с PowerShell [Core] 7.0, PowerShell-родной не существует способа постоянного обновления переменных среды, но его введение - обсуждается на GitHub .

Другими словами: , если вы хотите обновить не только определение на основе реестра, но и значение в текущем процессе вам нужно сделать оба звонка ; Например, для текущего пользователя:

# Windows only: Update / create a persistent definition for the current user,
#               stored in the registry.
[Environment]::SetEnvironmentVariable('EnvVarName', 'foo', 'User')

# Update value for current process too.
$env:EnvVarName = 'foo'

Или, больше в духе DRY:

'User', 'Process' | foreach {
  [Environment]::SetEnvironmentVariable('EnvVarName', 'foo', $_)
}

Если новое значение должно быть основано для существующего из заданной области реестра получить значение c для области видимости через System.Environment.GetEnvironmentVariable; Например:

# Get the registry-based *user* value 
[Environment]::GetEnvironmentVariable('Path', 'User')

Важные замечания для переменной среды Path ($env:PATH) в Windows:

  • Среда Path Эта особенность заключается в том, что это составное значение: при запуске процесса внутрипроцессное значение равно сцеплению значения Machine (локальный компьютер, для всех пользователей) и значение User (текущий пользователь).

  • Поэтому, если вы хотите изменить (добавить) существующий Path, лучше , а не , чтобы Определите новое значение, просто добавив к существующему значению в процессе ($env:Path), потому что вы будете дублировать Machine или User значений, в зависимости от того, на какую область вы нацеливаетесь.

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

    • Чтобы надежно сделать ту же модификацию эффективной в текущем процессе, тоже нетривиально, учитывая, что внутрипроцессная копия $env:Path могла быть изменена, однако в простом В случае добавления нового каталога к пути пользователя, вы можете просто сделать $env:Path += ';' + $newDir, вы можете избежать этого простого подхода и в других случаях, но учтите, что поведение может отличаться, учитывая, что порядок в которых каталоги перечислены в $env:Path значения.

Пример:

# New dir. to add to the *user's* path
$newDir = 'c:\foo\bin'

# Get current value *from the registry*
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')

# Append the new dir and save back to the registry.
[Environment]::SetEnvironmentVariable('Path', ($userPath + ';' + $newDir), 'User')

# To also update the current process, append $newDir to the in-process
# variable, $env:Path
$env:Path += ';' + $newDir

В качестве отступления: Вкл Unix -подобные платформы , разделитель - :, а не ; (отражен в [System.IO.Path]::PathSeparator, а с учетом регистра имя переменной равно Path. Как указано,. NET принципиально не предлагает упорство nt определения переменных среды на Unix -подобных платформах (по состоянию на NET Core 3.1), потому что на разных платформах нет унифицированного собственного механизма для этого.


[1] На Unix -подобных платформах с таргетингом на User или Machine тихо игнорируется с. NET Core 3.1

[ 2] Предупреждение : новые процессы, созданные непосредственно текущим сеансом PowerShell (прямой вызов, Start-Process, Start-Job), делают не , но все же видят изменения в реестре, поскольку они наследуют текущая среда сеанса.

0 голосов
/ 20 февраля 2020

Он добавлен к $env:PATH в области процесса, что означает, что он не задан как переменная пользователя или машинная переменная, а новое значение не существует за пределами текущего сеанса PowerShell. Вы не увидите переменную среды, установленную таким образом, в диалоговом окне «Переменные среды» в разделе «Свойства системы».

Если вы хотите установить постоянную переменную среды в области действия User или Machine из PowerShell, вы может, но вы должны вызвать специальный метод для этого из Environment класса, SetEnvironmentVariable:

# Set system (machine) level environment variable
[Environment]::SetEnvironmentVariable( 'VARIABLE_NAME', 'VARIABLE_VALUE', [EnvironmentVariableTarget]::Machine )

# Set user level environment variable
[Environment]::SetEnvironmentVariable( 'VARIABLE_NAME', 'VARIABLE_VALUE', [EnvironmentVariableTarget]::User )

Вы также можете использовать этот метод для установки Process переменная уровня среды, но вы уже можете сделать это с помощью синтаксиса $env:VARIABLE_NAME = 'VARIABLE_VALUE', который идиоматически c для PowerShell.


Я запутался, потому что я уже добавил папку в систему Переменные path

Вероятно, здесь произошло то, что вы открыли сеанс PowerShell, затем перешли в диалоговое окно Environment Variables и задали значение переменной. Проблема в том, что обычно переменные окружения, включая PATH, читаются только при запуске процесса. В большинстве случаев вам просто нужно перезапустить сеанс PowerShell, чтобы получить новые значения.

Если у вас установлен Chocolatey, вы можете использовать команду refreshenv, которая считывает текущие сохраненные переменные среды из реестра и сбрасывает переменные в текущем процессе. Если вы хотите реализовать подобные вещи самостоятельно, вот источник для этого . Хотя он написан как сценарий cmd, вы можете переопределить логи c в PowerShell самостоятельно или просто скопировать исходный код сценария для использования.


Кроме того, не добавляйте . на ваш путь. Несмотря на удобство, он обходит встроенные меры безопасности PowerShell. Добавьте каталог с вашими программами / сценариями, которые вы хотите запустить по команде, непосредственно в PATH или вызовите их из текущего каталога, добавив команду с .\. Например:

.\My-ScriptInThisDirectory.ps1
0 голосов
/ 20 февраля 2020

Если вы разберете эту команду, вы назначите новую строку переменной $ env: Path. Строка:

"$($env.Path);."

Когда вы помещаете $, за которым следует набор parens (), внутри строки в двойных кавычках, PowerShell оценивает содержимое паренов и помещает выходные данные этой оценки. в строку. См. Справку для about_Quoting_Rules в справке PowerShell или здесь в разделе об оценке выражений. Поэтому:

PS C:> $A = "abc"
PS C:> $B = "AB$($A)CD"
PS C:> $B
ABabcCD

Поэтому отправленная вами команда добавляет ";." до конца вашего пути. При этом "." будет автоматически расширяться до текущего каталога, поэтому при каждом запуске вы будете добавлять точку с запятой плюс текущий каталог к ​​переменной $ env: PATH.

Надеюсь, это поможет.

...