Каков наилучший способ определить местоположение текущего скрипта PowerShell? - PullRequest
463 голосов
/ 29 марта 2011

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

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

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

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

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

Ответы [ 13 ]

753 голосов
/ 29 марта 2011

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
58 голосов
/ 29 марта 2011

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

для 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
}
14 голосов
/ 29 марта 2011

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

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

function Get-Script-Directory
{
    $scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
    return Split-Path $scriptInvocation.MyCommand.Path
}
13 голосов
/ 20 января 2017

Для Powershell 3 +

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

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

11 голосов
/ 13 октября 2016

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

$PSCommandPath | Split-Path -Parent
10 голосов
/ 25 февраля 2016

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

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

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

7 голосов
/ 09 апреля 2016

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

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

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

7 голосов
/ 15 апреля 2014

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

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

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

5 голосов
/ 25 апреля 2019

Я всегда использую этот маленький фрагмент кода, который работает для 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...