PowerShell: เรียกใช้คำสั่งจากไดเรกทอรีของสคริปต์


144

ฉันมีสคริปต์ PowerShell ที่ทำสิ่งต่าง ๆ โดยใช้ไดเรกทอรีปัจจุบันของสคริปต์ ดังนั้นเมื่ออยู่ในไดเรกทอรี.\script.ps1ดังกล่าว

ตอนนี้ฉันต้องการเรียกสคริปต์นั้นจากไดเรกทอรีอื่นโดยไม่เปลี่ยนไดเรกทอรีอ้างอิงของสคริปต์ ดังนั้นฉันต้องการโทร..\..\dir\script.ps1และยังต้องการให้สคริปต์ทำงานตามที่เรียกจากภายในไดเรกทอรี

ฉันจะทำเช่นนั้นได้อย่างไรหรือฉันจะแก้ไขสคริปต์เพื่อให้สามารถเรียกใช้จากไดเรกทอรีใด ๆ

คำตอบ:


200

คุณหมายถึงคุณต้องการเส้นทางของสคริปต์เพื่อให้คุณสามารถอ้างอิงไฟล์ถัดจากสคริปต์ได้หรือไม่ ลองสิ่งนี้:

$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Write-host "My directory is $dir"

คุณสามารถได้รับข้อมูลจำนวนมากจาก $ MyInvocation และคุณสมบัติของมัน

หากคุณต้องการอ้างอิงไฟล์ในไดเรกทอรีการทำงานปัจจุบันคุณสามารถใช้ Resolve-Path หรือ Get-ChildItem:

$filepath = Resolve-Path "somefile.txt"

แก้ไข (ตามความคิดเห็นจาก OP):

# temporarily change to the correct folder
Push-Location $folder

# do stuff, call ant, etc

# now back to previous directory
Pop-Location

อาจมีวิธีอื่นในการบรรลุสิ่งที่คล้ายกันโดยใช้ Invoke-Command เช่นกัน


1
อืมโอเคบางทีฉันน่าจะเห็นสคริปท์ของตัวเองดีขึ้นเล็กน้อย จริงๆแล้วมันเป็นสคริปต์ที่เรียกantด้วยพารามิเตอร์บางอย่าง ดังนั้นฉันต้องโทรantจากโฟลเดอร์นั้นเพื่อให้แน่ใจว่าพบไฟล์การกำหนดค่าอย่างถูกต้อง เป็นการดีที่ฉันกำลังมองหาบางอย่างที่จะเปลี่ยนไดเรกทอรีการดำเนินการภายในสคริปต์นั้นชั่วคราว
สะกิด

3
อาในกรณีนี้คุณจะต้องการPush-LocationและPop-Location
JohnL

5
ระมัดระวังเกี่ยวกับว่า $ MyInvocation เป็นบริบทที่สำคัญฉันมักจะทำ $ ScriptPath = (Get-Variable MyInvocation -Scope Script) .Value.MyCommand.Path ซึ่งทำงานได้จากการซ้อนหรือฟังก์ชั่นใด ๆ

39

หากคุณกำลังเรียกใช้แอพที่ใช้ในเครื่องคุณต้องกังวลว่าจะ[Environment]::CurrentDirectoryไม่เกี่ยวกับ$PWDไดเรกทอรีปัจจุบันของ PowerShell ด้วยเหตุผลหลายประการ PowerShell ไม่ได้ตั้งค่าไดเรกทอรีการทำงานปัจจุบันของกระบวนการเมื่อคุณตั้งค่าตำแหน่งหรือ Push-Location ดังนั้นคุณต้องแน่ใจว่าคุณทำเช่นนั้นหากคุณใช้แอปพลิเคชัน (หรือ cmdlets) ที่คาดว่าจะตั้งค่า

ในสคริปต์คุณสามารถทำสิ่งนี้:

$CWD = [Environment]::CurrentDirectory

Push-Location $MyInvocation.MyCommand.Path
[Environment]::CurrentDirectory = $PWD
##  Your script code calling a native executable
Pop-Location

# Consider whether you really want to set it back:
# What if another runspace has set it in-between calls?
[Environment]::CurrentDirectory = $CWD

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

หมายเหตุสองประการเกี่ยวกับสาเหตุที่ทำไม PowerShell ถึงไม่ถูกตั้งค่าโดยอัตโนมัติ:

  1. PowerShell สามารถเป็นแบบมัลติเธรด คุณสามารถมีหลาย Runspaces (ดู RunspacePool และโมดูล PSThreadJob) ทำงานพร้อมกันภายในกระบวนการเดียว แต่ละพื้นที่$PWDทำงานมีไดเรกทอรีการทำงานปัจจุบัน แต่มีเพียงกระบวนการเดียวและสภาพแวดล้อมเดียวเท่านั้น
  2. แม้ว่าคุณจะเป็นเธรดเดียว แต่$PWDก็ไม่ได้เป็น CurrentDirectory ที่ถูกต้องตามกฎหมายเสมอไป (เช่นคุณอาจใส่ CD เข้าไปในผู้ให้บริการสตรีเช่น)

หากคุณต้องการใส่ลงในพรอมต์ของคุณ (ซึ่งจะทำงานใน runspace หลักเธรดเดียวเท่านั้น) คุณต้องใช้:

[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem

4
ไม่เปลี่ยนไดเรกทอรีการทำงานของกระบวนการเนื่องจากผู้ให้บริการเส้นทาง: คุณอาจกำลัง CD'ing ในรีจิสทรีฐานข้อมูล SQL หรือ IIS hive เป็นต้น ...
piers7

1
ใช่. ฉันรู้ว่านั่นคือประเด็นสุดท้าย "บันทึกสุดท้าย" พวกเขาสามารถมี (อย่างที่ฉันทำในฟังก์ชั่นพรอมต์ของฉัน) อัปเดตเป็นตำแหน่งปัจจุบันของผู้ให้บริการ FileSystem เหมือนเชลล์อื่น ๆ ในโลก
Jaykul

2
เทพเจ้าแห่งสคริปต์ศักดิ์สิทธิ์ฉันรู้สึกผิดหวังมาก.\_/.- สำหรับครึ่งวันที่ฉันถูกฆ่า! ผู้คนอย่างจริงจัง? อย่างจริงจัง? ..
ulidtko

2
ส่วนใหญ่ไม่จำเป็นในขณะนี้ PowerShell รุ่นที่ทันสมัยกว่านี้จะกำหนดไดเรกทอรีทำงานเมื่อเปิดตัวแอปแบบไบนารี
Jaykul

1
วิธีการนี้จะล้มเหลวไปที่การฟื้นฟูเดิมเมื่อที่แตกต่างจาก[Environment]::CurrentDirectory $PWDสิ่งที่ถูกต้องที่จะทำคือเก็บไว้ในตัวแปร$origEnvDir = [Environment]::CurrentDirectoryแล้วเรียกคืนมันใน[Environment]::CurrentDirectory = $origEnvDirภายหลัง
ปัจจุบัน

37

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

$PSScriptRoot - the directory where the script exists, not the target directory the script is running in
$PSCommandPath - the full path of the script

ตัวอย่างเช่นฉันมีสคริปต์ $ profile ที่ค้นหาไฟล์โซลูชัน visual studio และเริ่มมัน ฉันต้องการเก็บเส้นทางแบบเต็มเมื่อไฟล์โซลูชันเริ่มต้น แต่ฉันต้องการบันทึกไฟล์ที่มีสคริปต์ต้นฉบับอยู่ ดังนั้นฉันจึงใช้ $ PsScriptRoot


12

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

$ currentPath = แยกเส้นทาง ((MyInvocation -Signable -Scope 0) .Value) .MyCommand.Path

นำเข้าโมดูล "$ currentPath \ sqlps.ps1"


คุณต้องการตั้งค่า -Scope เป็น Script

9

นี้จะทำงานได้ดี

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir

อย่าลืมที่จะโทรPop-Locationในตอนท้ายเพื่อกลับเส้นทางไปสู่สถานะเดิม
Lam Le

2

ฉันกำลังมองหาวิธีแก้ปัญหานี้อยู่พักหนึ่งโดยไม่ต้องใช้สคริปต์ใด ๆ จาก CLI นี่คือวิธีที่ฉันทำ xD:

  • นำทางไปยังโฟลเดอร์ที่คุณต้องการเรียกใช้สคริปต์ (สิ่งสำคัญคือคุณมีแท็บที่สมบูรณ์)

    ..\..\dir

  • ตอนนี้ล้อมรอบตำแหน่งด้วยเครื่องหมายคำพูดคู่และภายในนั้นเพิ่มcdดังนั้นเราจึงสามารถเรียกใช้ตัวอย่าง PowerShell

    "cd ..\..\dir"

  • เพิ่มคำสั่งอื่นเพื่อเรียกใช้สคริปต์โดยคั่นด้วยโดย;มีตัวคั่นคำสั่งใน powershell

    "cd ..\..\dir\; script.ps1"

  • ในที่สุดก็เรียกใช้กับอินสแตนซ์ของ PowerShell อื่น

    start powershell "cd..\..\dir\; script.ps1"

จะเป็นการเปิดหน้าต่าง PowerShell ใหม่ไปที่..\..\dirเรียกใช้script.ps1และปิดหน้าต่าง


โปรดทราบว่า ";" เพียงแค่แยกคำสั่งเช่นคุณพิมพ์ทีละคนถ้าล้มเหลวครั้งแรกที่สองจะทำงานและต่อไปหลังจากและต่อไปหลังจาก ... ถ้าคุณต้องการให้หน้าต่าง PowerShell ใหม่เปิดคุณเพิ่ม -noexit ในคำสั่งผ่าน โปรดทราบว่าฉันไปที่โฟลเดอร์ที่ต้องการเป็นครั้งแรกเพื่อให้ฉันสามารถใช้ความสำเร็จของแท็บ (คุณไม่สามารถใส่เครื่องหมายคำพูดคู่)

start powershell "-noexit cd..\..\dir\; script.ps1"

ใช้เครื่องหมายคำพูดคู่""เพื่อให้คุณสามารถส่งผ่านไดเรกทอรีที่มีช่องว่างในชื่อเช่น

start powershell "-noexit cd '..\..\my dir'; script.ps1"


0

ฉันสร้างหนึ่งซับจากโซลูชันของ @ JohnL:

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