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

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

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

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

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

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

Ответ 1

PowerShell 3+

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

PowerShell 2

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

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

Ответ 2

Если вы создаете модуль 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.

Ответ 3

Для 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
}

Ответ 4

Для PowerShell 3+

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

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

Ответ 5

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

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

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

Ответ 6

Очень похоже на уже опубликованные ответы, но pipeопроводы кажутся более похожими на PowerShell:

$PSCommandPath | Split-Path -Parent

Ответ 7

Я использую автоматическую переменную $ ExecutionContext. Это работает от PowerShell 2 и позже.   $ ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath( '\')

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

Ответ 8

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

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

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

Ответ 9

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

Я не уверен насчет других, но я работаю в среде с компьютерами как на 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
}

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

Ответ 10

Я всегда использую этот небольшой фрагмент, который работает для PowerShell и ISE одинаково:

# Set active path to script-location:
$path = $MyInvocation.MyCommand.Path
if (!$path) {
    $path = $psISE.CurrentFile.Fullpath
}
if ($path) {
    $path = Split-Path $path -Parent
}
Set-Location $path

Ответ 11

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

Ответ 12

Я обнаружил, что старые решения, опубликованные здесь, не работают для меня на PowerShell V5. Я придумал это:

try {
    $scriptPath = $PSScriptRoot
    if (!$scriptPath)
    {
        if ($psISE)
        {
            $scriptPath = Split-Path -Parent -Path $psISE.CurrentFile.FullPath
        }
        else {
            Write-Host -ForegroundColor Red "Cannot resolve script file path"
            exit 1
        }
    }
}
catch {
    Write-Host -ForegroundColor Red "Caught Exception: $($Error[0].Exception.Message)"
    exit 2
}

Write-Host "Path: $scriptPath"

Ответ 13

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