จะคืนชื่อของสคริปต์การโทรจากโมดูล 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 และการดำเนินการ sctipt คือ 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 cmdlet ซึ่งส่งคืนอาร์เรย์ของวัตถุเฟรมสแต็ก คุณสามารถใช้สิ่งนี้เพื่อระบุสคริปต์การโทรจนถึงบรรทัดโค้ด

โมดูล: 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 นั้นสัมพันธ์กับการกำหนดขอบเขต หากคุณต้องการเส้นทางของสคริปต์ของคุณ อย่าใส่ไว้ในฟังก์ชัน หากคุณต้องการเรียกใช้คำสั่งคุณก็ห่อมัน

คุณยังสามารถใช้ callstack ตามที่แนะนำได้ แต่ต้องระวังกฎการกำหนดขอบเขต

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

สำหรับชาว Google ที่กำลังมองหาโซลูชันการคัดลอกและวางอย่างรวดเร็ว นี่คือสิ่งที่ใช้ได้กับ 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