如何从Powershell模块返回调用脚本的名称?

时间:2014-04-29 16:18:09

标签: powershell powershell-v2.0

我有两个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)。我怎么能这样做?

9 个答案:

答案 0 :(得分:12)

在您的模块中使用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

答案 1 :(得分:7)

我相信你可以使用Get-PSCallStack cmdlet,它返回一个堆栈帧对象数组。您可以使用它来识别调用脚本到代码行。

模块:test.psm1

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

输出:

myTest.ps1: Line 2

答案 2 :(得分:2)

使用$ 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与范围有关。如果您想要脚本的路径,请不要将其包含在函数中。如果要调用该命令,则将其包装起来。

您也可以按照建议使用callstack,但要注意范围规则。

答案 3 :(得分:1)

要引用调用脚本的调用信息,请使用:

@(Get-PSCallStack)[1].InvocationInfo

e.g:

@(Get-PSCallStack)[1].InvocationInfo.MyCommand.Name

答案 4 :(得分:0)

我在尝试了几种技术之后今天就用这个。

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

答案 5 :(得分:0)

这为脚本路径提供了尾部反斜杠作为一个变量,脚本名称作为另一个变量。

该路径适用于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(' \')

答案 6 :(得分:0)

如果您想要一种更可重用的方法,则可以使用:

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

我面临的挑战是拥有一个可以在模块内重用的功能。其他所有条件都假定该脚本直接调用了模块函数,并且即使将其删除(即使仅执行了1步),结果也就是模块文件名。但是,如果源脚本正在调用模块中的一个函数,又在模块中调用另一个函数,那么这是我所见的唯一可以确保您获取源脚本信息的答案。 / p>

当然,这种方法基于@iRon和@James发布的内容。

答案 7 :(得分:0)

对于正在寻找快速复制粘贴解决方案的Google员工, 这是在Powershell 5.1中起作用的地方

在您的模块内部:

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

这将仅输出调用位于模块中的功能的脚本名称(ScriptName.ps1)。

答案 8 :(得分:0)

我在my module中使用它:

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
}