Как найти исходный путь к исполняемому скрипту? [дубликат]

этот вопрос уже есть ответ здесь:

Я хочу знать, с какого пути был запущен мой сценарий выполнения.
Это часто не будет $pwd.

Мне нужно вызывать другие скрипты, которые находятся в структура папок относительно моего скрипта, и хотя я мог бы жестко кодировать пути, это и неприятно, и немного больно в шее при попытке продвижения от "dev" до "test" до "production".

7 ответов


вездесущий скрипт первоначально разместил Джеффри До Смерти команды PowerShell (приведено в Скайлер) и вариации, опубликованные Китом Седирком и EBGreen, все страдают от серьезного недостатка-сообщает Ли код, что вы ожидаете, зависит от того, где вы его называете!

мой код ниже преодолевает эту проблему путем простой ссылки скрипт объем вместо родитель область применения:

function Get-ScriptDirectory
{
    Split-Path $script:MyInvocation.MyCommand.Path
}

чтобы проиллюстрировать проблему, я создал тестовый автомобиль, который evalutes целевое выражение в четырех различных способов. (Заключенные в квадратные скобки термины являются ключами к следующей таблице результатов.)

  1. встроенный код [inline]
  2. встроенная функция, т. е. функция в основной программе [встроенная функция]
  3. функция точечного источника, т. е. та же функция перемещена в отдельную.ps1 файл [точечный источник]
  4. функции модуля, т. е. та же функция перешла в отдельную.файл psm1 [модуль]

последние два столбца показывают результат использования script scope (т. е. $script:) или родительской scope (with-scope 1). Результат "script" означает, что вызов правильно сообщил о местоположении скрипта. Результат "модуль" означает, что вызов сообщил о местоположении модуля, содержащего функцию, а не сценарий, который вызвал функцию; это указывает на недостаток обеих функций, которые вы не удается поместить функцию в модуль.

установка проблемы модуля в сторону замечательное наблюдение из таблицы заключается в том, что использование подхода родительской области в большинстве случаев не удается (на самом деле, в два раза чаще, чем это удается).

table of input combinations

наконец, вот тестовое транспортное средство:

function DoubleNested()
{
    "=== DOUBLE NESTED ==="
    NestCall
}

function NestCall()
{
    "=== NESTED ==="
    "top level:"
    Split-Path $script:MyInvocation.MyCommand.Path
    #$foo = (Get-Variable MyInvocation -Scope 1).Value
    #Split-Path $foo.MyCommand.Path
    "immediate func call"
    Get-ScriptDirectory1
    "dot-source call"
    Get-ScriptDirectory2
    "module call"
    Get-ScriptDirectory3
}

function Get-ScriptDirectory1
{
    Split-Path $script:MyInvocation.MyCommand.Path
    # $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    # Split-Path $Invocation.MyCommand.Path
}

. .\ScriptDirFinder.ps1
Import-Module ScriptDirFinder -force

"top level:"
Split-Path $script:MyInvocation.MyCommand.Path
#$foo = (Get-Variable MyInvocation -Scope 1).Value
#Split-Path $foo.MyCommand.Path

"immediate func call"
Get-ScriptDirectory1
"dot-source call"
Get-ScriptDirectory2
"module call"
Get-ScriptDirectory3

NestCall
DoubleNested

содержимое ScriptDirFinder.ps1:

function Get-ScriptDirectory2
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

содержимое ScriptDirFinder.psm1 успешно:

function Get-ScriptDirectory3
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

Я не знаком с тем, что было введено в PowerShell 2, но вполне может быть, что script scope не существовала в PowerShell 1, в то время как Джеффри Сновер опубликовал свой пример.

Я был удивлен, когда, хотя я обнаружил, что его пример кода распространился повсюду в интернете, он сразу же потерпел неудачу, когда я попробовал! Но это было потому, что я использовал его иначе, чем пример Snover (я назвал его не в script-top, а изнутри другой функции (мой " вложенный дважды" образец.))

обновление 2011.09.12

вы можете прочитать об этом с другими советами и трюками по модулям в моей только что опубликованной статье о Simple-Talk.com: далее по кроличьей норе: модули PowerShell и инкапсуляция.


вы отметили свой вопрос для Powershell версии 1.0, однако, если у вас есть доступ к Powershell версии 3.0, вы знаете, что есть $PSCommandPathи$PSScriptRootчто делает получение пути скрипта немного проще. Пожалуйста, обратитесь к раздел "Другие функции скрипта" на этой странице для получения дополнительной информации.


мы используем такой код в большинстве наших скриптов в течение нескольких лет без проблем:

#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir  = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1

недавно я столкнулся с той же проблемой. Следующая статья помогла мне решить эту проблему:http://blogs.msdn.com/powershell/archive/2007/06/19/get-scriptdirectory.aspx

Если вас не интересует, как это работает, вот весь код, который вам нужен в статье:

function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

и затем вы получаете путь, просто делая:

$path = Get-ScriptDirectory

Я думаю, что вы можете найти путь запуска скрипта через

$MyInvocation.MyCommand.Path

надеюсь, что это помогает !

Седрик


Это одна из тех странностей (на мой взгляд по крайней мере) в ПС. Я уверен, что для этого есть веская причина, но мне все еще кажется странным. Итак:

Если вы находитесь в скрипте,но не в функции, то $myInvocation.InvocationName даст вам полный путь, включая имя сценария. Если вы находитесь в скрипте и внутри функции, то $myInvocation.ScriptName даст вам то же самое.


спасибо msorens! Это действительно помогло мне с моим пользовательским модулем. В случае, если кто-то заинтересован в создании своего собственного, вот как структурирован мой.

MyModule (folder)
 - MyModule.psd1 (help New-ModuleManifest)
 - MyScriptFile.ps1 (ps1 files are easy to test)

затем вы ссылаетесь на MyScriptFile.ps1 в MyModule.psd1 все. Ссылка на .ps1 в массиве NestedModules будет размещать функции в состоянии сеанса модуля, а не в состоянии глобального сеанса. (Как написать манифест модуля)

NestedModules = @('.\MyScriptFile.ps1','.\MyOtherScriptFile.ps1')

содержание MyScriptFile.ps1

function Get-ScriptDirectory {
    Split-Path $script:MyInvocation.MyCommand.Path
}

try {
    Export-ModuleMember -Function "*-*"
}
catch{}

try / catch скрывает ошибку от Export-ModuleMember при запуске MyScriptFile.ps1

скопировать библиотека mymodule каталог к одному из путей, найденных здесь $env: PSModulePath

PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule

CommandType     Name                                               ModuleName                                                                                                                                                
-----------     ----                                               ----------                                                                                                                                                
Function        Get-ScriptDirectory                                MyModule