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


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

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

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

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

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

11 379

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 > Help 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