วิธีรับไดเร็กทอรีปัจจุบันของ cmdlet ที่ถูกเรียกใช้งาน


202

นี่ควรจะเป็นงานง่าย ๆ แต่ฉันได้เห็นหลายครั้งในการหาพา ธ ไปยังไดเร็กตอรี่ที่ cmdlet ที่เรียกใช้งานอยู่ด้วยความสำเร็จที่หลากหลาย ตัวอย่างเช่นเมื่อผมดำเนินการC:\temp\myscripts\mycmdlet.ps1ที่มีการตั้งค่าไฟล์ที่C:\temp\myscripts\settings.xmlฉันต้องการที่จะสามารถที่จะเก็บในตัวแปรภายในC:\temp\myscriptsmycmdlet.ps1

นี่เป็นวิธีหนึ่งที่ใช้งานได้ (แม้ว่าจะค่อนข้างยุ่งยาก):

$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
$settingspath = $directorypath + '\settings.xml'

อีกคนหนึ่งแนะนำวิธีแก้ปัญหานี้ซึ่งทำงานได้เฉพาะในสภาพแวดล้อมการทดสอบของเรา:

$settingspath = '.\settings.xml'

ฉันชอบวิธีการหลังมากและต้องการให้วิเคราะห์ filepath เป็นพารามิเตอร์ในแต่ละครั้ง แต่ฉันไม่สามารถทำให้มันทำงานบนสภาพแวดล้อมการพัฒนาของฉันได้ ฉันควรทำอย่างไร มีบางสิ่งที่เกี่ยวข้องกับการกำหนดค่า PowerShell หรือไม่


11
โปรดทราบว่าชื่อที่ไม่ชัดเจนของคำถามนี้ส่งผลให้คำตอบด้านล่างแก้ปัญหาที่แตกต่างกันหนึ่งในสองปัญหาโดยไม่ระบุว่า: (a) วิธีอ้างอิงตำแหน่งปัจจุบัน (ไดเรกทอรี) หรือ (b) วิธีอ้างอิงตำแหน่งสคริปต์ที่ทำงานอยู่ ( ไดเร็กทอรีที่สคริปต์รันอยู่ซึ่งอาจเป็นไดเร็กทอรีปัจจุบันหรือไม่ก็ได้)
mklement0

คำตอบ:


143

$MyInvocation.MyCommand.Pathวิธีที่น่าเชื่อถือในการทำเช่นนี้เป็นเช่นเดียวกับคุณแสดงให้เห็นว่า

การใช้พา ธ ที่เกี่ยวข้องจะขึ้นอยู่กับ $ pwd ใน PowerShell ไดเรกทอรีปัจจุบันสำหรับแอปพลิเคชันหรือไดเรกทอรีทำงานปัจจุบันสำหรับ. NET API

PowerShell v3 + :

$PSScriptRootใช้ตัวแปรอัตโนมัติ


6
คุณช่วยอธิบายฉันเกี่ยวกับเส้นทางอสังหาริมทรัพย์ได้อย่างไร $ MyInvocation.MyCommand | gm ไม่แสดงคุณสมบัติดังกล่าวในรายชื่อสมาชิก
Vitaliy Markitanov

19
ทำไมไม่ใช้เพียง $ PSScriptRoot ดูเหมือนน่าเชื่อถือมากขึ้น
mBrice1024

@ user2326106 คุณช่วยอธิบายความแตกต่างระหว่าง$PSScriptRootและ$MyInvocation.MyCommand.Path?
duct_tape_coder

1
คำตอบนี้ไม่สมบูรณ์
K - ความเป็นพิษใน SO กำลังเพิ่มขึ้น

คำตอบนี้ไม่สมบูรณ์
stackleit

263

ใช่ว่าควรจะทำงาน แต่ถ้าคุณต้องการเห็นเส้นทางสัมบูรณ์นี่คือทั้งหมดที่คุณต้องการ:

(Get-Item -Path ".\").FullName

4
ขอบคุณนี่เป็นวิธีที่ยอดเยี่ยมในการค้นหาเส้นทางแบบเต็มจากเส้นทางญาติ เช่น (รับรายการ -Path $ myRelativePath -Verbose) .FullName
dlux

ขอบคุณสำหรับสิ่งนี้. คำตอบอื่น ๆ ไม่ได้ทำงานกับสคริปต์ Powershell ที่คอมไพล์ด้วย EXE
Zach Alexander

10
นี่คือผิด นี่เป็นไดเรกทอรีปัจจุบันของกระบวนการซึ่งสามารถอยู่ที่ใดก็ได้ ตัวอย่างเช่นถ้าบรรทัดคำสั่งของฉันไดเรกทอรีปัจจุบันC:\mydirและฉันวิงวอนขอคำสั่งC:\dir1\dir2\dir3\mycmdlet.ps1แล้วนี้จะแก้ไขเพื่อไม่C:\mydir C:\dir1\dir2\dir3การเรียกใช้งานโปรแกรมเรียกทำงานใหม่นั้นมีปัญหาเดียวกันเนื่องจากไดเรกทอรีปัจจุบันได้รับการสืบทอดมาจากกระบวนการหลัก
jpmc26

85

วิธีที่ง่ายที่สุดดูเหมือนว่าจะใช้ตัวแปรที่กำหนดไว้ล่วงหน้าดังต่อไปนี้:

 $PSScriptRoot

about_Automatic_Variablesและabout_Scriptsทั้งสองรัฐ:

ใน PowerShell 2.0 ตัวแปรนี้ใช้ได้เฉพาะในโมดูลสคริปต์ (.psm1) เริ่มต้นใน PowerShell 3.0 ใช้ได้กับสคริปต์ทั้งหมด

ฉันใช้มันแบบนี้:

 $MyFileName = "data.txt"
 $filebase = Join-Path $PSScriptRoot $MyFileName

12
เป็นรุ่นเฉพาะ สิ่งนี้ต้องการ Powershell 3.0 เป็นอย่างน้อย
Marvin Dickhaus

1
นี่คือสิ่งที่ฉันต้องการในการอ้างอิงไฟล์ในตำแหน่งเดียวกับสคริปต์ - ขอบคุณ!
Adam Prescott

นี่คือคำตอบที่ดีที่สุดเพราะจะให้เส้นทางที่คุณใช้สคริปต์ PS อย่างแม่นยำซึ่งเป็นรากฐานของการดำเนินการสคริปต์ของคุณ ไม่สนใจไดเรกทอรีการทำงานปัจจุบันของคุณจากที่คุณเรียกใช้สคริปต์ของคุณ +1
RBT

@ MarvinDickhaus นั่นเป็นเหตุผลว่าทำไมจึงจำเป็นต้องใช้ "Set-StrictMode -Version 3.0" ในสคริปต์ของคุณส่วนใหญ่ :) ขอบคุณมากสำหรับลิงก์!
Alexander Shapkin

44

คุณยังสามารถใช้:

(Resolve-Path .\).Path

ส่วนในวงเล็บส่งคืน PathInfoวัตถุ

(มีให้ตั้งแต่ PowerShell 2.0)


2
นี่คือผิด นี่เป็นไดเรกทอรีปัจจุบันของกระบวนการซึ่งสามารถอยู่ที่ใดก็ได้ ตัวอย่างเช่นถ้าบรรทัดคำสั่งของฉันไดเรกทอรีปัจจุบันC:\mydirและฉันวิงวอนขอคำสั่งC:\dir1\dir2\dir3\mycmdlet.ps1แล้วนี้จะแก้ไขเพื่อไม่C:\mydir C:\dir1\dir2\dir3การเรียกใช้งานโปรแกรมเรียกทำงานใหม่นั้นมีปัญหาเดียวกันเนื่องจากไดเรกทอรีปัจจุบันได้รับการสืบทอดจากกระบวนการหลัก
jpmc26

3
ขอบคุณ! ฉันยังเข้าใจชื่อของคำถามนี้ผิดและคำตอบนี้เป็นสิ่งที่ฉันต้องการ อย่างไรก็ตาม ... มันไม่ได้ตอบคำถาม
Ryan The Leach

33

เส้นทางมักเป็นโมฆะ ฟังก์ชั่นนี้ปลอดภัยยิ่งขึ้น

function Get-ScriptDirectory
{
    $Invocation = (Get-Variable MyInvocation -Scope 1).Value;
    if($Invocation.PSScriptRoot)
    {
        $Invocation.PSScriptRoot;
    }
    Elseif($Invocation.MyCommand.Path)
    {
        Split-Path $Invocation.MyCommand.Path
    }
    else
    {
        $Invocation.InvocationName.Substring(0,$Invocation.InvocationName.LastIndexOf("\"));
    }
}

1
ทำไมต้อง -Scope 1 ไม่ใช่ -Scope 0
suiwenfeng

1
รับตัวแปร: หมายเลขขอบเขต '1' เกินจำนวนขอบเขตที่ใช้งานอยู่
suiwenfeng

2
คุณได้รับข้อผิดพลาดนี้เนื่องจากคุณไม่มีขอบเขตหลัก -Scope พารามิเตอร์รับตัวแปรในขอบเขตที่ระบุ 1 ในกรณีนี้คือขอบเขตหลัก สำหรับข้อมูลเพิ่มเติมดูบทความด้านเทคนิคเกี่ยวกับ Get-Variable ( technet.microsoft.com/en-us/library/hh849899.aspx )
Christian Flem

27

ลอง :

(Get-Location).path

หรือ:

($pwd).path

ฉันลืมไปตลอด$pwd/ $PWDเมื่อใดก็ตามที่ฉันหยุดพักจาก PowerShell! IMO ที่มีประโยชน์มากยิ่งขึ้น ...
kayleeFrye_onDeck


11

ฉันชอบโซลูชันบรรทัดเดียว :)

$scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent

นี่เป็นทางออกที่ดีที่สุด
Teoman shipahi

ใช่เหมาะกับฉัน pwd ของฉันคือไดเรกทอรีผู้ใช้ของฉันและฉันกำลังเรียกใช้สคริปต์ในไดเรกทอรีอื่น (B) มันให้ (B)
andrew pate



1

คุณคิดว่าการใช้ '. \' เป็นเส้นทางหมายความว่าเป็นเส้นทางการขอร้อง แต่ไม่ใช่ตลอดเวลา ตัวอย่างถ้าคุณใช้ภายในงาน ScriptBlock ในกรณีนี้มันอาจชี้ไปที่% profile% \ Documents


1

ฟังก์ชั่นนี้จะตั้งค่าตำแหน่งที่พรอมต์เป็นเส้นทางสคริปต์จัดการกับวิธี differents เพื่อรับสคริปต์ระหว่าง vscode, psise และ pwd:

function Set-CurrentLocation
{
    $currentPath = $PSScriptRoot                                                                                                     # AzureDevOps, Powershell
    if (!$currentPath) { $currentPath = Split-Path $pseditor.GetEditorContext().CurrentFile.Path -ErrorAction SilentlyContinue }     # VSCode
    if (!$currentPath) { $currentPath = Split-Path $psISE.CurrentFile.FullPath -ErrorAction SilentlyContinue }                       # PsISE

    if ($currentPath) { Set-Location $currentPath }
}

0

สำหรับสิ่งที่ควรค่าแก่การเป็นโซลูชันบรรทัดเดียวด้านล่างเป็นโซลูชันที่ใช้งานได้สำหรับฉัน

$currFolderName = (Get-Location).Path.Substring((Get-Location).Path.LastIndexOf("\")+1)

1 /ในตอนท้ายคือการละเว้น

ขอบคุณโพสต์ด้านบนโดยใช้cmdlet รับตำแหน่ง


0

คำตอบส่วนใหญ่ไม่ทำงานเมื่อทำการดีบั๊กใน IDE ต่อไปนี้:

  • PS-ISE (PowerShell ISE)
  • รหัส VS (รหัส Visual Studio)

เพราะในนั้น$PSScriptRootว่างเปล่าและResolve-Path .\(และ similars) จะทำให้เส้นทางไม่ถูกต้อง

คำตอบของ Freakydindeเป็นเพียงสิ่งเดียวที่แก้ไขสถานการณ์เหล่านั้นได้ดังนั้นฉันจึงได้รับการโหวต แต่ฉันไม่คิดSet-Locationว่าคำตอบนั้นเป็นสิ่งที่ต้องการจริงๆ ดังนั้นฉันจึงแก้ไขและทำให้รหัสมีความชัดเจนขึ้นเล็กน้อย:

$directorypath = if ($PSScriptRoot) { $PSScriptRoot } `
    elseif ($psise) { $psise.CurrentFile.FullPath } `
    elseif ($psEditor) { split-path $psEditor.GetEditorContext().CurrentFile.Path }

-1

เพื่อขยายคำตอบของ @Cradle: คุณสามารถเขียนฟังก์ชั่นเอนกประสงค์ที่จะให้ผลลัพธ์เดียวกันกับคำถามของ OP:

Function Get-AbsolutePath {

    [CmdletBinding()]
    Param(
        [parameter(
            Mandatory=$false,
            ValueFromPipeline=$true
        )]
        [String]$relativePath=".\"
    )

    if (Test-Path -Path $relativePath) {
        return (Get-Item -Path $relativePath).FullName -replace "\\$", ""
    } else {
        Write-Error -Message "'$relativePath' is not a valid path" -ErrorId 1 -ErrorAction Stop
    }

}

-1

หากคุณต้องการชื่อของไดเรกทอรีปัจจุบันคุณสามารถทำสิ่งนี้:

((Get-Location) | Get-Item).Name

สมมติว่าคุณกำลังทำงานจาก C: \ Temp \ Location \ MyWorkingDirectory>

เอาท์พุต

MyWorkingDirectory


-1

ฉันมีปัญหาที่คล้ายกันและทำให้ฉันมีปัญหามากตั้งแต่ฉันทำโปรแกรมที่เขียนใน PowerShell (แอปพลิเคชัน GUI สำหรับผู้ใช้ปลายทาง) และฉันมีไฟล์และทรัพยากรจำนวนมากที่ฉันต้องโหลดจากดิสก์ .เพื่อแสดงไดเรกทอรีปัจจุบันไม่น่าเชื่อถือ มันควรจะเป็นตัวแทนของไดเรกทอรีการทำงานปัจจุบัน แต่ก็มักจะไม่ ปรากฏว่า PowerShell บันทึกสถานที่จากที่ PowerShell .ได้รับการเรียกภายใน เพื่อความแม่นยำมากขึ้นเมื่อ PowerShell เริ่มขึ้นครั้งแรกจะเริ่มต้นภายในไดเรกทอรีผู้ใช้ตามบ้านของคุณ โดยปกติจะเป็นไดเรกทอรีของบัญชีผู้ใช้ของคุณเช่นC:\USERS\YOUR USER NAME. หลังจากนั้น PowerShell เปลี่ยนไดเรกทอรีเป็นไดเรกทอรีที่คุณเรียกใช้หรือไดเรกทอรีที่สคริปต์ที่คุณกำลังเรียกใช้อยู่ก่อนที่จะแสดงพร้อมท์ PowerShell หรือเรียกใช้สคริปต์ แต่สิ่งนี้เกิดขึ้นหลังจากแอพ PowerShell เริ่มต้นเองภายในไดเรกทอรีผู้ใช้ภายในบ้านของคุณ

และ.แสดงถึงไดเรกทอรีเริ่มต้นภายใน PowerShell ที่เริ่มต้น ดังนั้น.แสดงเฉพาะไดเรกทอรีปัจจุบันในกรณีที่คุณเรียกใช้ PowerShell จากไดเรกทอรีที่ต้องการ หากคุณเปลี่ยนไดเรกทอรีในรหัส PowerShell ในภายหลังการเปลี่ยนแปลงจะไม่ปรากฏ.ในทุกกรณี ในบางกรณี.หมายถึงไดเรกทอรีการทำงานปัจจุบันและในไดเรกทอรีอื่นที่ PowerShell (ตัวเองไม่ใช่สคริปต์) ถูกเรียกสิ่งที่สามารถนำไปสู่ผลลัพธ์ที่ไม่สอดคล้องกัน ด้วยเหตุนี้ฉันจึงใช้สคริปต์ตัวเรียกใช้ สคริปต์ PowerShell ด้วยคำสั่งเดียวภายใน: แสดงถึงไดเรกทอรีปัจจุบัน แต่จะใช้งานได้หากคุณไม่เปลี่ยนไดเรกทอรีในภายหลังในรหัส PowerShell ในกรณีของสคริปต์ฉันใช้ Invoker script ซึ่งคล้ายกับสคริปต์ล่าสุดที่ฉันพูดถึงยกเว้นมีตัวเลือกไฟล์: POWERSHELLสคริปต์ที่มีอยู่ภายในคำสั่งเดียว: ที่จะให้แน่ใจว่า PowerShell ถูกเรียกใช้จากไดเรกทอรีที่ต้องการและทำให้.POWERSHELL -FILE DRIVE:\PATH\SCRIPT NAME.PS1ในกรณีของสคริปต์ผมใช้ทรงสคริปต์ซึ่งคล้ายกับคนสุดท้ายที่ผมกล่าวถึงยกเว้นว่ามันจะมีตัวเลือกไฟล์:เพื่อให้แน่ใจว่า PowerShell เริ่มต้นภายในไดเรกทอรีการทำงานปัจจุบัน

เพียงคลิกที่สคริปต์จะเรียกใช้ PowerShell จากไดเรกทอรีผู้ใช้ตามบ้านของคุณไม่ว่าสคริปต์จะอยู่ที่ใด มันเป็นผลมาจากไดเรกทอรีการทำงานปัจจุบันเป็นไดเรกทอรีที่สคริปต์ตั้งอยู่ แต่กำลังร้องขอไดเรกทอรี PowerShellC:\USERS\YOUR USER NAMEและด้วยการ.ส่งกลับหนึ่งในสองไดเรกทอรีเหล่านี้ขึ้นอยู่กับสถานการณ์สิ่งที่ไร้สาระ

แต่เพื่อหลีกเลี่ยงความยุ่งยากทั้งหมดและการใช้สคริปต์ตัวเรียกใช้คุณสามารถใช้อย่างใดอย่างหนึ่ง$PWDหรือ$PSSCRIPTROOTแทน.การแสดงไดเรกทอรีปัจจุบันขึ้นอยู่กับสภาพอากาศที่คุณต้องการแสดงไดเรกทอรีการทำงานปัจจุบันหรือไดเรกทอรีที่สคริปต์ถูกเรียกใช้ และถ้าคุณด้วยเหตุผลบางอย่างต้องการดึงอีกสองไดเรกทอรีที่.$HOMEผลตอบแทนที่คุณสามารถใช้

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

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