Когда PowerShell напрямую вызывает *.ps1
сценарий , этот сценарий выполняет в процессе , в том же пространстве выполнения, что и вызывающая сторона, и, следовательно, скрипт по умолчанию видит то же текущее местоположение (рабочий каталог), что и вызывающий .
В качестве отступления: наоборот, если скрипт меняет текущее местоположение, вызывающий видит это тоже после завершения работы скрипта (подробности см. ниже).
Если вы не видите это поведение, это означает, что какой-то закулисный код меняет текущее местоположение.
Единственный способ реально увидеть это происходит в следующих сценариях:
Если (a) ваш файл $PROFILE
содержит команду Set-Location
/ Push-Location
, которая явно переключается на вашу домашнюю папку или (b) (как в вашем случае, как мы сейчасзнать) если в модуле автозагрузки есть - неработающий код, который делает это при (автоматическом) импорте [1] и :
Вы вызываете PowerShell через CLI (powershell.exe
для Windows PowerShell , pwsh
для PowerShell Core ) без переключателя -NoProfile
;например, powershell -File someScript.ps1
На Unix-подобных платформах ваш сценарий реализован и называется как исполняемый сценарий оболочки без расширений со строкой shebang (не включающий -NoProfile
- подробности см. ниже).
Если вы запускаете скрипт с помощью одной из следующих команд / функций:
Через Start-Job
(в дочернем процессе) или Start-ThreadJob
(в новом пространстве выполнения), по крайней мере, в настоящее время (PowerShell Core 7.0.0-preview.4)
- Примечание. Эти два командлетане ведут себя точно так же, что само по себе проблематично, но большая проблема в том, что они просто не наследуют текущее местоположение вызывающего - см. эту проблему GitHub .
Через PowerShell SDK в новом пространстве выполнения.
Кроме этого, я могу толькосм. случайный код, основанный на событиях, создающий ваш симптом, такой как следующее - бессмысленное - переопределение интерактивной подсказкиng определяющая функция, prompt
, чтобы заставить ее тихо переключаться в каталог $HOME
после каждой команды:
# !! Obviously, do NOT do this.
function prompt {
# Print the usual prompt string.
"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "
# Quietly return to $HOME
Set-Location $HOME
}
В остальной части ответа обсуждается связанный сценарий, который может представлять интерес.
Выполнение сценария PowerShell со своим собственным каталогом в качестве рабочего каталога (текущее местоположение):
В PowerShell v3 + автоматическая переменная $PSScriptRoot
содержит полный путь к каталогу, в котором выполняется сценарийнаходится
Если вам нужно, чтобы ваш скрипт выполнялся со своим собственным каталогом в качестве рабочего каталога (текущее местоположение), используйте следующий подход:
# Switch to this script's directory.
Push-Location -LiteralPath $PSScriptRoot
try {
# Your script's body here.
# ...
$PWD # output the current location
}
finally {
# Restore the previous location.
Pop-Location
}
Примечание:
Причина явного восстановления предыдущего расположения (каталога) заключается в том, что PowerShell запускает сценарии (.ps1
файлы) в процессе , поэтому, если скрипт изменяет текущее местоположение с помощью Set-Location
или Push-Location
, он вступает в силу session-globalbally ;то есть новое местоположение сохраняется даже после выхода из сценария.
На Unix-подобных платформах (Linux, macOS) с PowerShell Core теперь у вас есть возможность создавать (без расширения) исполняемые сценарии оболочки со строкой shebang ;такие сценарии выполняются в дочернем процессе , и поэтому нет необходимо восстановить предыдущее местоположение (каталог) .
- К сожалению, доступ к информации о собственном вызове сценария, включая
$PSScriptRoot
, нарушен в сценариях на основе shebang, начиная с PowerShell Core 7.0.0-preview.4, как обсуждалось в этот выпуск GitHub .
[1] Ни один модуль не должен изменять глобальное состояние сеанса при импорте (кроме импорта его команд), но технически это возможно , а именно, если вы размещаете такие команды, как Set-Location
в области верхнего уровня файла *.psm1
модуля скрипта или в сценариях, которые запускаются в области вызывающего абонента с помощью записи ScriptsToProcess
module-manifest. Даже двоичные командлеты могут выполнять код во время импорта через интерфейс System.Management.Automation.IModuleAssemblyInitializer
- см. этот ответ .