ฉันจะรับไฟล์ปฏิบัติการ PowerShell ปัจจุบันได้อย่างไร


100

หมายเหตุ: PowerShell 1.0
ฉันต้องการรับชื่อไฟล์ PowerShell ที่เรียกใช้งานปัจจุบัน นั่นคือถ้าฉันเริ่มเซสชันของฉันแบบนี้:

powershell.exe .\myfile.ps1

ฉันต้องการรับสตริง". \ myfile.ps1" (หรืออะไรทำนองนั้น) แก้ไข : "myfile.ps1"ดีกว่า
ความคิดใด ๆ ?


ขอบคุณคำตอบปัจจุบันเกือบจะเหมือนกัน แต่ฉันต้องการแค่ชื่อไฟล์ (ไม่ใช่ทั้งเส้นทาง) ดังนั้นคำตอบที่ยอมรับคือ @ Keith's แม้ว่า +1 ทั้งสองคำตอบ ตอนนี้ฉันรู้แล้วเกี่ยวกับ $ MyInvocation thingy :-)
Ron Klein

วิธีการรับสคริปต์หลักจากสคริปต์ที่รวม?
Florin Sabau

คำตอบ:


78

ฉันได้พยายามสรุปคำตอบต่างๆที่นี่อัปเดตสำหรับ PowerShell 5:

  • หากคุณใช้เฉพาะ PowerShell 3 ขึ้นไปให้ใช้ไฟล์ $PSCommandPath

  • หากต้องการความเข้ากันได้กับเวอร์ชันเก่าให้ใส่ shim:

    if ($PSCommandPath -eq $null) { function GetPSCommandPath() { return $MyInvocation.PSCommandPath; } $PSCommandPath = GetPSCommandPath; }

    สิ่งนี้จะเพิ่ม$PSCommandPathหากยังไม่มีอยู่

    รหัส shim สามารถเรียกใช้งานได้ทุกที่ (ระดับบนสุดหรือภายในฟังก์ชัน) แม้ว่า$PSCommandPathตัวแปรจะอยู่ภายใต้กฎการกำหนดขอบเขตปกติ (เช่นถ้าคุณใส่ shim ในฟังก์ชันตัวแปรจะถูกกำหนดขอบเขตไว้ที่ฟังก์ชันนั้นเท่านั้น)

รายละเอียด

มี 4 วิธีที่แตกต่างกันที่ใช้ในคำตอบต่างๆดังนั้นฉันจึงเขียนสคริปต์นี้เพื่อสาธิตแต่ละข้อ (บวก$PSCommandPath):

function PSCommandPath() { return $PSCommandPath; }
function ScriptName() { return $MyInvocation.ScriptName; }
function MyCommandName() { return $MyInvocation.MyCommand.Name; }
function MyCommandDefinition() {
    # Begin of MyCommandDefinition()
    # Note: ouput of this script shows the contents of this function, not the execution result
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()
}
function MyInvocationPSCommandPath() { return $MyInvocation.PSCommandPath; }

Write-Host "";
Write-Host "PSVersion: $($PSVersionTable.PSVersion)";
Write-Host "";
Write-Host "`$PSCommandPath:";
Write-Host " *   Direct: $PSCommandPath";
Write-Host " * Function: $(ScriptName)";
Write-Host "";
Write-Host "`$MyInvocation.ScriptName:";
Write-Host " *   Direct: $($MyInvocation.ScriptName)";
Write-Host " * Function: $(ScriptName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Name:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Name)";
Write-Host " * Function: $(MyCommandName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Definition:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Definition)";
Write-Host " * Function: $(MyCommandDefinition)";
Write-Host "";
Write-Host "`$MyInvocation.PSCommandPath:";
Write-Host " *   Direct: $($MyInvocation.PSCommandPath)";
Write-Host " * Function: $(MyInvocationPSCommandPath)";
Write-Host "";

เอาท์พุต:

PS C:\> .\Test\test.ps1

PSVersion: 5.1.19035.1

$PSCommandPath:
 *   Direct: C:\Test\test.ps1
 * Function: C:\Test\test.ps1

$MyInvocation.ScriptName:
 *   Direct:
 * Function: C:\Test\test.ps1

$MyInvocation.MyCommand.Name:
 *   Direct: test.ps1
 * Function: MyCommandName

$MyInvocation.MyCommand.Definition:
 *   Direct: C:\Test\test.ps1
 * Function:
    # Begin of MyCommandDefinition()
    # Note this is the contents of the MyCommandDefinition() function, not the execution results
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()


$MyInvocation.PSCommandPath:
 *   Direct:
 * Function: C:\Test\test.ps1

หมายเหตุ:

  • ดำเนินการจากแต่สคริปต์ที่เกิดขึ้นจริงC:\C:\Test\test.ps1
  • ไม่มีวิธีใดที่บอกคุณถึงเส้นทางการเรียกใช้ที่ผ่าน ( .\Test\test.ps1)
  • $PSCommandPath เป็นวิธีเดียวที่เชื่อถือได้ แต่ได้รับการแนะนำใน PowerShell 3
  • สำหรับเวอร์ชันก่อนหน้า 3 ไม่มีวิธีการเดียวที่ใช้ได้ทั้งภายในและภายนอกฟังก์ชัน

7
สำหรับทุกคนที่อ่านวันนี้ (2017) ควรอ่านโพสต์นี้เป็นคำตอบที่ถูกต้อง! +1
Collin Chaffin

2
@CollinChaffin: เห็นด้วยและตอนนี้ (2017) สิ่งที่รองรับอย่างน้อยที่สุดในปัจจุบันคือ Windows 7 ดังนั้นจึงไม่มีเหตุผลที่จะไม่ใช้$PSCommandPathหากไม่จำเป็นต้องใช้ระบบเดิม (WindowsXP)
tukan

ตัวอย่างโค้ดแรกมีข้อบกพร่องเนื่องจากมีคำจำกัดความของฟังก์ชันเดียวกันสองคำ ( function PSCommandPath) และการอ้างอิงถึงฟังก์ชันที่ไม่ถูกต้อง ( Write-Host " * Direct: $PSCommandPath"; Write-Host " * Function: $(ScriptName)";- หรือฉันมองข้ามสิ่งที่ชัดเจนไปหรือไม่
Mike L'Angelo

@ MikeL'Angelo คุณพูดถูก! ไม่มีใครสังเกตเห็นเป็นเวลา 3 ปี คงขอบคุณ ผลลัพธ์และข้อสรุปจะเหมือนกัน
gregmac

82

แม้ว่าคำตอบปัจจุบันจะถูกต้องในกรณีส่วนใหญ่ แต่ก็มีบางสถานการณ์ที่ไม่สามารถให้คำตอบที่ถูกต้องได้ หากคุณใช้ภายในฟังก์ชันสคริปต์ของคุณแล้ว:

$MyInvocation.MyCommand.Name 

ส่งคืนชื่อของฟังก์ชันแทนชื่อของชื่อของสคริปต์

function test {
    $MyInvocation.MyCommand.Name
}

จะให้คุณ " ทดสอบ " ไม่ว่าสคริปต์ของคุณจะตั้งชื่ออย่างไร คำสั่งที่ถูกต้องสำหรับการเรียกชื่อสคริปต์เสมอ

$MyInvocation.ScriptName

สิ่งนี้จะส่งคืนเส้นทางแบบเต็มของสคริปต์ที่คุณกำลังเรียกใช้ หากคุณต้องการเพียงแค่ชื่อไฟล์สคริปต์มากกว่ารหัสนี้ควรช่วยคุณ:

split-path $MyInvocation.PSCommandPath -Leaf

6
โปรดทราบว่าที่ระดับบนสุด Scriptname ไม่ได้กำหนดด้วย posh v4 ฉันต้องการใช้ที่ระดับบนสุดคือ $ MyInvocation.MyCommand.Definition สำหรับเส้นทางแบบเต็มหรือชื่อตามคำตอบอื่น ๆ
AnneTheAgile

30
$MyInvocation.ScriptNameคืนสตริงว่างให้ฉัน PS v3.0
JohnC

4
@JohnC $MyInvocation.ScriptNameทำงานจากภายในฟังก์ชันเท่านั้น ดูคำตอบของฉันด้านล่าง
gregmac

73

หากคุณต้องการเพียงชื่อไฟล์ (ไม่ใช่เส้นทางแบบเต็ม) ให้ใช้สิ่งนี้:

$ScriptName = $MyInvocation.MyCommand.Name

33

ลองทำดังต่อไปนี้

$path =  $MyInvocation.MyCommand.Definition 

นี่อาจไม่ได้ให้เส้นทางจริงที่พิมพ์ลงไป แต่จะให้เส้นทางที่ถูกต้องไปยังไฟล์


1
@ แฮมมิชถามโดยเฉพาะว่าถูกเรียกจากไฟล์หรือไม่
JaredPar

FYI: นี่ให้เส้นทางแบบเต็มและชื่อไฟล์ (Powershell 2.0)
Ralph Willgoss

ฉันกำลังค้นหาคำสั่งนี้ ขอบคุณ JaredPar! :)
sqlfool

ใช้ Split-Path เพื่อรับไดเร็กทอรี? $path = Split-Path $MyInvocation.MyCommand.Definition -Parent
Underverse

8

หากคุณกำลังมองหาไดเร็กทอรีปัจจุบันที่สคริปต์กำลังทำงานอยู่คุณสามารถลองใช้ไดเร็กทอรีนี้:

$fullPathIncFileName = $MyInvocation.MyCommand.Definition
$currentScriptName = $MyInvocation.MyCommand.Name
$currentExecutingPath = $fullPathIncFileName.Replace($currentScriptName, "")

Write-Host $currentExecutingPath

1
มันจะทำงานไม่ถูกต้องC:\ilike.ps123\ke.ps1ใช่ไหม
fridojet

@fridojet - ไม่แน่ใจอย่าอยู่ใกล้เครื่อง PS เพื่อทดสอบ ทำไมคุณไม่ลองดูล่ะ?
Ryk

ไม่ใช่แค่คำถามเกี่ยวกับวาทศิลป์ ;-) - มันคงเป็นเหตุผลเพราะReplace()วิธีการนี้แทนที่เข็มที่เกิดขึ้นทุกครั้ง (ไม่ใช่แค่เหตุการณ์สุดท้าย) และฉันก็ทดสอบด้วย อย่างไรก็ตามเป็นความคิดที่ดีที่จะทำบางอย่างเช่นการลบสตริง
fridojet

... แล้วString.TrimEnd()( $currentExecutingPath = $fullPathIncFileName.TrimEnd($currentScriptName)) ล่ะ? - ทำงานอย่างถูกต้อง: "Ich bin Hamster".TrimEnd("ster")ส่งคืนIch bin Hamและ"Ich bin Hamsterchen".TrimEnd("ster")ส่งคืนIch bin Hamsterchen(แทนIch bin Hamchen) - ดี!
fridojet

$currentScriptPath = $MyInvocation.MyCommand.Definition; $currentScriptName = $MyInvocation.MyCommand.Name; $currentScriptDir = $currentScriptPath.Substring(0,$currentScriptPath.IndexOf($currentScriptName));
YP

7

ระวัง: ไม่เหมือน$PSScriptRootและ$PSCommandPathอัตโนมัติตัวแปรที่ PSScriptRootและPSCommandPathคุณสมบัติของ$MyInvocationตัวแปรอัตโนมัติมีข้อมูลเกี่ยวกับคนทรงหรือโทรสคริปต์ไม่สคริปต์ปัจจุบัน

เช่น

PS C:\Users\S_ms\OneDrive\Documents> C:\Users\SP_ms\OneDrive\Documents\DPM ...
=!C:\Users\S_ms\OneDrive\Documents\DPM.ps1

... ที่DPM.ps1ประกอบด้วย

Write-Host ("="+($MyInvocation.PSCommandPath)+"!"+$PSCommandPath)

5

ตามที่ระบุไว้ในคำตอบก่อนหน้านี้การใช้ "$ MyInvocation" อาจมีปัญหาในการกำหนดขอบเขตและไม่จำเป็นต้องให้ข้อมูลที่สอดคล้องกัน (ค่าที่ส่งคืนเทียบกับค่าการเข้าถึงโดยตรง) ฉันพบว่าเมธอด "สะอาดที่สุด" (สอดคล้องกันมากที่สุด) ในการรับข้อมูลสคริปต์เช่นพา ธ สคริปต์ชื่อพาร์มบรรทัดคำสั่ง ฯลฯ โดยไม่คำนึงถึงขอบเขต (ในการเรียกฟังก์ชันหลักหรือตามมา / ซ้อนกัน) คือการใช้ "Get- ตัวแปร "บน" MyInvocation "...

# Get the MyInvocation variable at script level
# Can be done anywhere within a script
$ScriptInvocation = (Get-Variable MyInvocation -Scope Script).Value

# Get the full path to the script
$ScriptPath = $ScriptInvocation.MyCommand.Path

# Get the directory of the script
$ScriptDirectory = Split-Path $ScriptPath

# Get the script name
# Yes, could get via Split-Path, but this is "simpler" since this is the default return value
$ScriptName = $ScriptInvocation.MyCommand.Name

# Get the invocation path (relative to $PWD)
# @GregMac, this addresses your second point
$InvocationPath = ScriptInvocation.InvocationName

ดังนั้นคุณจะได้รับข้อมูลเดียวกันกับ $ PSCommandPath แต่มีอีกมากมายในข้อตกลง ไม่แน่ใจ แต่ดูเหมือนว่า "Get-Variable" จะไม่สามารถใช้งานได้จนกว่า PS3 จึงไม่ได้รับความช่วยเหลือมากนักสำหรับระบบเก่า (ไม่ได้อัปเดต)

นอกจากนี้ยังมีแง่มุมที่น่าสนใจบางประการเมื่อใช้ "-Scope" เนื่องจากคุณสามารถย้อนรอยเพื่อรับชื่อ ฯลฯ ของฟังก์ชันการโทรได้ 0 = ปัจจุบัน 1 = พาเรนต์ ฯลฯ

หวังว่านี่จะเป็นประโยชน์บ้าง

อ้างอิงhttps://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable


4

ฉันจะเถียงว่ามีวิธีการที่ดีกว่าโดยการตั้งค่าขอบเขตของตัวแปร $ MyInvocation.MyCommand.Path:

เช่น> $ script : MyInvocation.MyCommand.Name

วิธีนี้ใช้ได้ในทุกสถานการณ์ของการร้องขอ:

เช่น Somescript.ps1

function printme () {
    "In function:"
    ( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
    ( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
    ( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
}
"Main:"
( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
" "
printme
exit

เอาท์พุท:

PS> powershell C:\temp\test.ps1
Main:
MyInvocation.ScriptName:
script:MyInvocation.MyCommand.Name: test.ps1
MyInvocation.MyCommand.Name: test.ps1

In function:
MyInvocation.ScriptName: C:\temp\test.ps1
script:MyInvocation.MyCommand.Name: test.ps1
MyInvocation.MyCommand.Name: printme

สังเกตว่าคำตอบที่ยอมรับข้างต้นไม่ส่งคืนค่าเมื่อเรียกจาก Main นอกจากนี้โปรดทราบว่าคำตอบที่ยอมรับข้างต้นจะแสดงเส้นทางแบบเต็มเมื่อคำถามขอชื่อสคริปต์เท่านั้น ตัวแปรที่กำหนดขอบเขตทำงานได้ในทุกที่

นอกจากนี้หากคุณต้องการเส้นทางแบบเต็มคุณจะโทร:

$script:MyInvocation.MyCommand.Path

1

ทำการทดสอบกับสคริปต์ต่อไปนี้ทั้งใน PS 2 และ PS 4 และได้ผลลัพธ์เหมือนกัน ฉันหวังว่านี่จะช่วยผู้คนได้

$PSVersionTable.PSVersion
function PSscript {
  $PSscript = Get-Item $MyInvocation.ScriptName
  Return $PSscript
}
""
$PSscript = PSscript
$PSscript.FullName
$PSscript.Name
$PSscript.BaseName
$PSscript.Extension
$PSscript.DirectoryName

""
$PSscript = Get-Item $MyInvocation.InvocationName
$PSscript.FullName
$PSscript.Name
$PSscript.BaseName
$PSscript.Extension
$PSscript.DirectoryName

ผล -

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      -1     -1      

C:\PSscripts\Untitled1.ps1
Untitled1.ps1
Untitled1
.ps1
C:\PSscripts

C:\PSscripts\Untitled1.ps1
Untitled1.ps1
Untitled1
.ps1
C:\PSscripts

1

สิ่งนี้สามารถใช้ได้กับเวอร์ชัน powershell ส่วนใหญ่:

(& { $MyInvocation.ScriptName; })

สิ่งนี้สามารถใช้ได้กับงานตามกำหนดเวลา

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.