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


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

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

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

7 57

7 ответов:

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

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

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

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

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

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

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

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.пс1

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