【问题标题】:How to return the name of the calling script from a Powershell Module?如何从 Powershell 模块返回调用脚本的名称?
【发布时间】:2022-03-19 09:34:10
【问题描述】:

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

【问题讨论】:

  • 我知道这对你来说可能只是一个学术练习,但为什么不直接从 myTest.ps1 脚本中调用 $MyInvocation.MyCommand.Name 来获取该信息呢?
  • 这不是学术练习。我已经发布了简单的示例代码来帮助回答者。我需要从模块中获取调用脚本的名称。
  • @JohnC:这个问题是关于调用脚本的,另一个问题是关于执行文件的。例如,如果 main.ps1 从 module.psm1 调用函数,调用脚本是 main.ps1,执行 sctipt 是 module.psm1

标签: powershell powershell-2.0


【解决方案1】:

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

【讨论】:

【解决方案2】:

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

模块:test.psm1

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

输出:

myTest.ps1: Line 2

【讨论】:

    【解决方案3】:

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

    您也可以按照建议使用调用堆栈,但请注意范围规则。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

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

        @(Get-PSCallStack)[1].InvocationInfo
        

        例如:

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            【解决方案7】:

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

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

            我遇到的挑战是有一个可以在模块中重用的函数。其他一切都假设脚本直接调用模块函数,如果它被删除甚至 1 步,那么结果将是模块文件名。但是,如果源脚本调用模块中的一个函数,而该函数又调用模块中的另一个函数,那么这是我见过的唯一可以确保您获得源脚本信息的答案。

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

            【讨论】:

              【解决方案8】:

              对于寻找快速复制粘贴解决方案的谷歌用户, 这是 Powershell 5.1 中的工作原理

              在您的模块内部:

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

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

              【讨论】:

                【解决方案9】:

                我在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
                }
                

                【讨论】:

                  【解决方案10】:

                  您可以从父作用域中获取自动变量 MyInvocation 并从那里获取名称。

                  Get-Variable -Scope:1 -Name:MyInvocation -ValueOnly
                  

                  我做了一个基本的测试来检查它是否总是能获得直接的父作用域,它的工作方式就像一种享受,而且速度非常快,而不是Get-PSCallStack

                  function ScopeTest () {
                      Write-Information -Message:'ScopeTest'
                  }
                  Write-nLog -Message:'nLog' -Type:110 -SetLevel:Verbose
                  ScopeTest
                  

                  【讨论】:

                    猜你喜欢
                    • 2011-08-27
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-01-09
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多