Вездесущий скрипт, изначально опубликованный Джеффри Сновером из команда PowerShell (приведенная в ответе Скайлера) и варианты, опубликованные Китом Седирком и EBGreen, страдают серьезным недостатком --сообщает ли код то, что вы ожидаете, зависит от того, где вы его вызываете!
В приведенном ниже коде эта проблема решается путем простой ссылки на область script вместо области parent:
function Get-ScriptDirectory
{
Split-Path $script:MyInvocation.MyCommand.Path
}
Чтобы проиллюстрировать проблему, я создал тестовую машину, которая оценивает целевое выражение четырьмя различными способами. (Термины в квадратных скобках являются ключами к следующей таблице результатов.)
- встроенный код [встроенный]
- встроенная функция, т.е. функция в основной программе [inline function]
- Функция с точечным источником, т. е. та же функция, перемещенная в отдельный файл .ps1 [точечный источник]
- Модульная функция, т.е. эта же функция вынесена в отдельный файл .psm1 [модуль]
Последние два столбца показывают результат использования области скрипта (например, $script:) или родительской области (с -scope 1). Результат «сценарий» означает, что вызов правильно сообщил о расположении сценария. Результат «модуль» означает, что вызов сообщил о расположении модуля, содержащего функцию, а не сценарий, вызвавший функцию; это указывает на недостаток обеих функций в том, что вы не можете поместить функцию в модуль.
Если оставить в стороне проблему с модулем, то замечательное наблюдение из таблицы заключается в том, что использование подхода с родительской областью в большинстве случаев терпит неудачу (фактически, в два раза чаще, чем успешно).
Наконец, вот тестовый автомобиль:
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, но вполне может быть, что в PowerShell 1 не существовало области сценария, когда Джеффри Сновер опубликовал свой пример.
Я был удивлен, когда, хотя я обнаружил, что его пример кода широко распространен в Интернете, он сразу же потерпел неудачу, когда я попробовал его! Но это было потому, что я использовал его не так, как в примере Сновера (я вызвал его не наверху скрипта, а внутри другой функции (мой пример с "вложенным дважды").)
Обновление 2011.09.12
Вы можете прочитать об этом вместе с другими советами и рекомендациями по модулям в моей только что опубликованной статье на Simple-Talk.com: Дальше по кроличьей норе: модули PowerShell и инкапсуляция.
person
Michael Sorens
schedule
08.08.2011