PowerShell: выполнить команду из каталога script

У меня есть PowerShell script, который делает некоторые вещи, используя текущий каталог script. Поэтому, когда внутри этого каталога работает .\script.ps1, он работает правильно.

Теперь я хочу называть это script из другого каталога без изменения справочного каталога script. Поэтому я хочу вызвать ..\..\dir\script.ps1 и все еще хочу, чтобы script вел себя так, как он был вызван изнутри его каталога.

Как мне это сделать или как мне изменить script, чтобы он мог запускаться из любого каталога?

Ответ 1

Вы хотите, чтобы вы использовали собственный путь script, чтобы ссылаться на файл рядом с script? Попробуйте следующее:

$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Write-host "My directory is $dir"

Вы можете получить много информации из $MyInvocation и ее свойств.

Если вы хотите ссылаться на файл в текущем рабочем каталоге, вы можете использовать Resolve-Path или Get-ChildItem:

$filepath = Resolve-Path "somefile.txt"

EDIT (на основе комментария от OP):

# temporarily change to the correct folder
Push-Location $folder

# do stuff, call ant, etc

# now back to previous directory
Pop-Location

Возможно, существуют и другие способы достижения чего-то подобного с помощью Invoke-Command.

Ответ 2

Если вы вызываете собственные приложения, вам нужно беспокоиться о [Environment]::CurrentDirectory, а не о текущем каталоге PowerShell $PWD. По разным причинам PowerShell не устанавливает текущий рабочий каталог процесса при установке Set-Location или Push-Location, поэтому вам необходимо убедиться в этом, если вы запускаете приложения (или командлеты), которые ожидают его установки.

В сценарии вы можете сделать это:

$CWD = [Environment]::CurrentDirectory

Push-Location $MyInvocation.MyCommand.Path
[Environment]::CurrentDirectory = $PWD
##  Your script code calling a native executable
Pop-Location

# Consider whether you really want to set it back:
# What if another runspace has set it in-between calls?
[Environment]::CurrentDirectory = $CWD

Там нет надежной альтернативы этому. Многие из нас помещают строку в нашу функцию приглашения, чтобы установить [Environment] :: CurrentDirectory... но это не поможет вам, когда вы меняете расположение в скрипте.

Два замечания о причине, по которой PowerShell не устанавливает это автоматически:

  1. PowerShell может быть многопоточным. Вы можете иметь несколько Runspaces (см. RunspacePool и модуль PSThreadJob), запущенных одновременно в одном процессе. Каждое пространство выполнения имеет собственный рабочий каталог $PWD, но там только один процесс и только одна среда.
  2. Даже если вы однопоточны, $PWD не всегда является допустимым CurrentDirectory (вы можете, например, вставить CD в поставщика реестра).

Если вы хотите поместить его в приглашение (которое будет выполняться только в основном пространстве выполнения, однопоточное), вам нужно использовать:

[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem

Ответ 3

Есть ответы с большим количеством голосов, но когда я прочитал ваш вопрос, я думал, что вы хотите знать каталог, где находится script, а не то, где работает script. Вы можете получить информацию с автоматическими переменными powershell

$PSScriptRoot - the directory where the script exists, not the target directory the script is running in
$PSCommandPath - the full path of the script

Например, у меня есть $profile script, который находит файл визуального студийного решения и запускает его. Я хотел сохранить полный путь после запуска файла решения. Но я хотел сохранить файл, где существует оригинальный script. Поэтому я использовал $PsScriptRoot.

Ответ 4

Я часто использовал следующий код для импорта модуля, который находится в том же каталоге, что и работающий script. Сначала он получит каталог, из которого работает powershell

$currentPath = Split-Path ((Get-Variable MyInvocation -Scope 0).Value).MyCommand.Path

import-module "$ currentPath\sqlps.ps1"

Ответ 5

Это будет нормально работать.

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir

Ответ 6

Ну, я искал решение для этого какое-то время, без каких-либо скриптов только от CLI. Вот как я это делаю xD:

  • Перейдите в папку, из которой вы хотите запустить script (важно то, что у вас есть завершение вкладок)

    ..\..\dir

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

    "cd ..\..\dir"

  • Добавьте еще одну команду для запуска script, разделенного ;, с разделителем команд в powershell

    "cd ..\..\dir\; script.ps1"

  • Наконец Запустите его с другим экземпляром powershell

    start powershell "cd..\..\dir\; script.ps1"

Это откроет новое окно powershell, перейдите к ..\..\dir, запустите script.ps1 и закроет окно.


Обратите внимание, что ";" просто отделяет команды, например, вы набирали их один за другим, если первый провал второй будет запущен, а затем следующий, и следующий после... Если вы хотите открыть новое окно powershell, вы добавите -noexit в переданную команду. Обратите внимание, что сначала я перейду к нужной папке, чтобы я мог использовать вкладки (вы не могли бы использовать двойные кавычки).

start powershell "-noexit cd..\..\dir\; script.ps1"

Используйте двойные кавычки "", чтобы вы могли передавать каталоги с пробелами в именах, например,

start powershell "-noexit cd '..\..\my dir'; script.ps1"