Каков наилучший способ определить местоположение текущего сценария PowerShell?

всякий раз, когда мне нужно ссылаться на общий модуль или скрипт, мне нравится использовать пути относительно текущего файла скрипта, таким образом, мой скрипт всегда может найти другие скрипты в библиотеке.

Итак, каков наилучший, стандартный способ определения каталога текущего скрипта? В настоящее время я делаю:

$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)

Я знаю, что в модулях (.psm1) вы можете использовать $PSScriptRoot чтобы получить эту информацию, но это не устанавливается в обычных скриптах (т. е. ps1 архив.)

каков канонический способ получить местоположение текущего файла сценария PowerShell?

11 ответов


PowerShell 3+

# This is an automatic variable set to the current file's/module's directory
$PSScriptRoot

PowerShell 2

до PowerShell 3 не было лучшего способа, чем запросить MyInvocation.MyCommand.Definition свойство для общих скриптов. Я имел следующая строка в верхней части практически каждого сценария powershell, который у меня был:

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition

Если вы создаете модуль V2, вы можете использовать автоматическую переменную $PSScriptRoot.

из PS > справка automatic_variable

$PSScriptRoot
       Contains the directory from which the script module is being executed.
       This variable allows scripts to use the module path to access other
       resources.

Для PowerShell 3.0

$PSCommandPath
    Contains the full path and file name of the script that is being run. 
    This variable is valid in all scripts.

функция:

function Get-ScriptDirectory {
    Split-Path -Parent $PSCommandPath
}

может быть, я что-то упускаю... но если вам нужен настоящий рабочий каталог, вы можете просто использовать это:(Get-Location).Path для строки или Get-Location для объекта.

Если вы не имеете в виду что-то вроде этого, что я понимаю, прочитав вопрос снова.

function Get-Script-Directory
{
    $scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
    return Split-Path $scriptInvocation.MyCommand.Path
}

Я использую автоматическая переменная $ExecutionContext, он работает с PowerShell 2 и более поздних версий.

$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\')

$ExecutionContext Содержит объект EngineIntrinsics, представляющий контекст выполнения узла Windows PowerShell. Вы можете используйте эту переменную для поиска объектов выполнения, которые доступно для командлетов.


Мне нужно было знать имя скрипта и откуда он выполняется.

префикс "$global: "в структуру MyInvocation возвращает полный путь и имя скрипта при вызове как из основного скрипта, так и из основной строки импортируемого .Файл библиотеки psm1 успешно. Он также работает из функции в импортированной библиотеке.

после долгих возни, я решил использовать $global: MyInvocation.InvocationName. Он надежно работает с запуском CMD, работает с Powershell и Исе. Как локальные, так и UNC запуски возвращают правильный путь.


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

Не уверен в других, но я работаю в среде с машинами на обеих версиях PowerShell 2 и 3, поэтому мне нужно было обрабатывать оба. Следующая функция предлагает изящный запасной вариант:

Function Get-PSScriptRoot
{
    $ScriptRoot = ""

    Try
    {
        $ScriptRoot = Get-Variable -Name PSScriptRoot -ValueOnly -ErrorAction Stop
    }
    Catch
    {
        $ScriptRoot = Split-Path $script:MyInvocation.MyCommand.Path
    }

    Write-Output $ScriptRoot
}

Это также означает, что функция относится к области скрипта, а не сфера родителей как подчеркнул Михаил Соренс в его блог


очень похоже на уже опубликованные ответы, но трубопровод кажется более похожим на PS.

$PSCommandPath | Split-Path -Parent

Для Powershell 3+

function Get-ScriptDirectory {
    if ($psise) {Split-Path $psise.CurrentFile.FullPath}
    else {$global:PSScriptRoot}
}

Я поместил эту функцию в свой профиль. Работает в ISE, используя выбор F8/Run тоже.


вы также можете рассмотреть split-path -parent $psISE.CurrentFile.Fullpath Если какой-либо из других методов не удастся. В частности, если вы запускаете файл для загрузки группы функций, а затем выполняете эти функции с-в оболочке ISE (или если вы запускаете-выбранный), кажется Get-Script-Directory функция, как указано выше, не работает.


function func1() 
{
   $inv = (Get-Variable MyInvocation -Scope 1).Value
   #$inv.MyCommand | Format-List *   
   $Path1 = Split-Path $inv.scriptname
   Write-Host $Path1
}

function Main()
{
    func1
}

Main