Параметр Powershell EnvironmentVariable работает в ISE, но не в консоли - PullRequest
3 голосов
/ 18 февраля 2020

У меня странное поведение Powershell, которое я должен понять sh.

Если я установил постоянную переменную среды и запустил процесс, подобный следующему

[Environment]::SetEnvironmentVariable('FOO','BAR','User')
Start-Process notepad

Это работает, как и ожидалось в редакторе ISE, и если я наберу его после одного в консоли. Однако если я запускаю его как . \ Script.ps1 Script из консоли, Start-Process будет игнорировать новую или измененную переменную среды. Даже переменная среды правильно установлена ​​перед выполнением Start-Process . Я проверил это, добавив Sleep и проверив диалог переменных среды вручную. Если сценарий запускается во второй раз, процесс будет считывать переменную среды, как и ожидалось, поскольку она уже была изменена.

Почему в этом случае поведение консоли не такое, как в ISE?

Я уже пробовал, имеет ли это отношение к указанным c сборкам, которые загружаются в ISE, а не в консоль, но это не так. Я также пытался запустить как STA , но он тоже не работал.

1 Ответ

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

Примечание. Этот ответ указывается от c до Windows, поскольку System.Environment.SetEnvironmentVariable поддерживает только изменение постоянных определений переменных среды (через целевые области User и Machine) там. Однако основы того, как PowerShell определяет среду дочернего процесса, применимы и к Unix -подобным платформам.

[Environment]::SetEnvironmentVariable() с целевой областью действия System.EnvironmentVariableTarget аргумент User или Machine только обновляет постоянные определения переменных среды в реестре - он также не обновляет текущий процесс в памяти переменные .

Напротив, цель Process обновляет только текущий процесс переменные непостоянно .
Таким образом, [Environment]::SetEnvironmentVariable('FOO','BAR','Process') является эквивалентом $env:FOO = 'BAR'

Start-Process по умолчанию использует текущие переменные среды процесса [1] и, следовательно, не видят переменные (пока), которые были созданы или обновлены путем нацеливания на области User или Machine в тот же процесс . [2]

Start-Process Параметр -UseNewEnvironment равен , в принципе предназначен для того, что вы хотите t: он предназначен для запуска нового процесса со значениями переменной среды , считанными из реестра , игнорируя значения вызывающего процесса - однако эта функция нарушена на PowerShell [Core ] v7.0 - см. этот выпуск GitHub .

Обходной путь предназначен для , а также определяет новую переменную в current процесс:

# Update both the registry and the current process.
foreach ($targetScope in 'User', 'Process') {
  [Environment]::SetEnvironmentVariable('FOO', 'BAR', $targetScope)
}

# Start a new process with the new value in effect.
Start-Process -NoNewWindow -Wait powershell '-c \"`$env:FOO is: $env:FOO\"'

Обратите внимание, что - в отличие от того, что -UseNewEnvironment должен сделать - это заставляет новый процесс наследовать все только для процесса (в памяти ) переменные / значения среды тоже.


[1] При запуске процессу присваивается блок переменных среды, часто копия родительского процесса блок (как это делает сам PowerShell по умолчанию при создании дочерних процессов). Этот блок запуска может отражать или не отражать текущие определения реестра. Внутрипроцессные модификации блока среды теряются при завершении процесса, если они явно не сохраняются, например, с [Environment]::SetEnvironmentVariable() и целевыми областями User или Machine. Как и все программы, которые изменяют постоянно определенные переменные среды, [Environment]::SetEnvironmentVariable() передает Windows сообщение WM_SETTINGCHANGE как уведомление об изменении, но немногие программы предназначены для его прослушивания, и поэтому лишь немногие обновляют свои переменные среды в процессе. в ответ (что не подходит для всех программ).

[2] Однако, если вы начинаете новый процесс как администратор с -Verb RunAs ( Windows -только) с использованием учетных данных текущего пользователя , новый процесс будет видеть новые / обновленные определения, поскольку тогда не использует текущий процесс переменные среды и вместо этого считывает текущие определения из реестра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...