Как вернуть имя вызывающего скрипта из модуля Powershell?

У меня есть два файла Powershell, модуль и скрипт, который вызывает модуль.

Модуль: test.psm1

Function Get-Info {
    $MyInvocation.MyCommand.Name
}

Скрипт: myTest.ps1

Import-Module C:\Users\moomin\Documents\test.psm1 -force
Get-Info

Когда я запускаю ./myTest.ps1, я получаю

Get-Info

Я хочу вернуть имя вызывающего скрипта (test.ps1). Как я могу это сделать?


person Mark Allison    schedule 29.04.2014    source источник
comment
Я понимаю, что это может быть просто академическим упражнением для вас, но почему бы просто не вызвать $MyInvocation.MyCommand.Name из сценария myTest.ps1, чтобы получить эту информацию?   -  person TheMadTechnician    schedule 29.04.2014
comment
Это не академическое упражнение. Я разместил простой пример кода, чтобы помочь ответчику. Мне нужно получить имя вызывающего скрипта из модуля.   -  person Mark Allison    schedule 29.04.2014
comment
@JohnC: Этот вопрос касается вызова скрипта, другой вопрос касается выполнения файла. Например, если main.ps1 вызывает функцию из module.psm1, вызывающим скриптом является main.ps1, а выполнением скрипта является module.psm1.   -  person Michael Freidgeim    schedule 14.07.2017


Ответы (9)


Вместо этого используйте PSCommandPath в своем модуле:
Пример test.psm1

function Get-Info{
    $MyInvocation.PSCommandPath
}

Пример myTest.ps1

Import-Module C:\Users\moomin\Documents\test.psm1 -force
Get-Info

Выход:

C:\Users\moomin\Documents\myTest.ps1

Если вам нужно только имя сценария, которым можно было бы управлять, выполнив

GCI $MyInvocation.PSCommandPath | Select -Expand Name

Это выведет:

myTest.ps1
person TheMadTechnician    schedule 29.04.2014
comment
К сожалению, это работает для PSv3+ Функция автоматической загрузки модуля - person iRon; 19.08.2018

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

Модуль: test.psm1

Function Get-Info {
    $callstack = Get-PSCallStack
    $callstack[1].Location
}

Выход:

myTest.ps1: Line 2
person James    schedule 30.04.2014

Использование $MyInvocation.MyCommand зависит от его области действия.

Простой пример (скрипта, расположенного: C:\Dev\Test-Script.ps1):

$name = $MyInvocation.MyCommand.Name;
$path = $MyInvocation.MyCommand.Path;

function Get-Invocation(){
   $path = $MyInvocation.MyCommand.Path;
   $cmd = $MyInvocation.MyCommand.Name; 
   write-host "Command : $cmd - Path : $path";
}

write-host "Command : $cmd - Path : $path";
Get-Invocation;

Вывод при запуске .\c:\Dev\Test-Script.ps1 :

Command : C:\Dev\Test-Script.ps1 - Path : C:\Dev\Test-Script.ps1
Command : Get-Invocation - Path : 

Как видите, $MyInvocation зависит от области видимости. Если вам нужен путь к вашему скрипту, не заключайте его в функцию. Если вы хотите, чтобы команда вызывалась, вы ее обертываете.

Вы также можете использовать стек вызовов, как было предложено, но помните о правилах области видимости.

person Harald F.    schedule 30.04.2014

Я использовал это сегодня после того, как попробовал пару методов.

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$ScriptName = $MyInvocation.MyCommand | select -ExpandProperty Name
Invoke-Expression ". $Script\$ScriptName"
person BeastianSTi    schedule 17.10.2014

Чтобы обратиться к информации о вызове вызывающего скрипта, используйте:

@(Get-PSCallStack)[1].InvocationInfo

e.g.:

@(Get-PSCallStack)[1].InvocationInfo.MyCommand.Name
person iRon    schedule 21.12.2017

Это обеспечивает путь к сценарию с завершающей обратной косой чертой в качестве одной переменной и имя сценария в качестве другой.

Путь работает с Powershell 2.0, 3.0, 4.0 и, возможно, 5.0. Где с Posershell теперь доступен $PSscriptroot.

$_INST = $myinvocation.mycommand.path.substring(0,($myinvocation.mycommand.path.length - $MyInvocation.mycommand.name.length))

$_ScriptName = $myinvocation.mycommand.path.substring($MyInvocation.MyCommand.Definition.LastIndexOf('\'),($MyInvocation.mycommand.name.length +1))

$_ScriptName = $_ScriptName.TrimStart('\')

person DeployGuy    schedule 10.04.2015

Если вам нужен более многоразовый подход, вы можете использовать:

function Get-CallingFileName
{
    $cStack = @(Get-PSCallStack)
    $cStack[$cStack.Length-1].InvocationInfo.MyCommand.Name
}

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

Конечно, этот подход основан на том, что опубликовали @iRon и @James.

person Josh Bailey    schedule 02.10.2019

Для тех, кто ищет решение для быстрого копирования и вставки, вот что работает в Powershell 5.1.

Внутри вашего модуля:

$Script = (Get-PSCallStack)[2].Command

Это выведет только имя скрипта (ScriptName.ps1), который вызвал функцию, расположенную в модуле.

person metablaster    schedule 23.12.2019

Я использую это в моем модуле:

function Get-ScriptPath {
    [CmdletBinding()]
    param (
        [string]
        $Extension = '.ps1'
    )

    # Allow module to inherit '-Verbose' flag.
    if (($PSCmdlet) -and (-not $PSBoundParameters.ContainsKey('Verbose'))) {
        $VerbosePreference = $PSCmdlet.GetVariableValue('VerbosePreference')
    }

    # Allow module to inherit '-Debug' flag.
    if (($PSCmdlet) -and (-not $PSBoundParameters.ContainsKey('Debug'))) {
        $DebugPreference = $PSCmdlet.GetVariableValue('DebugPreference')
    }
    
    $callstack = Get-PSCallStack

    $i = 0
    $max = 100

    while ($true) {
        if (!$callstack[$i]) {
            Write-Verbose "Cannot detect callstack frame '$i' in 'Get-ScriptPath'."
            return $null
        }

        $path = $callstack[$i].ScriptName

        if ($path) {
            Write-Verbose "Callstack frame '$i': '$path'."
            $ext = [IO.Path]::GetExtension($path)
            if (($ext) -and $ext -eq $Extension) {
                return $path
            }
        }

        $i++

        if ($i -gt $max) {
            Write-Verbose "Exceeded the maximum of '$max' callstack frames in 'Get-ScriptPath'."
            return $null
        }
    }

    return $null
}
person Alek Davis    schedule 15.08.2020