Рабочий каталог скрипта PowerShell (текущее местоположение) - PullRequest
0 голосов
/ 08 октября 2019

Когда я запускаю скрипт PowerShell из любой папки (например, C:\Scripts), «текущей» папкой PowerShell внутри скрипта всегда является папка профиля пользователя (например, c:\users\Joe) (тестирование со скриптом только с Get-Location)

Но должна быть папка, из которой был запущен скрипт ...

как я могу это исправить?

1 Ответ

2 голосов
/ 08 октября 2019

Когда 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 - см. этот ответ .

...