PowerShell: Komut dosyasının dizinindeki komutu çalıştır


144

Komut dosyasının geçerli dizinini kullanarak bazı şeyler yapan bir PowerShell komut dosyası var. Bu dizinin içindeyken, çalışma .\script.ps1düzgün çalışır.

Şimdi bu betiği, betiğin referans dizinini değiştirmeden farklı bir dizinden çağırmak istiyorum. Bu yüzden aramak ..\..\dir\script.ps1ve hala bu komut dosyasının dizininin içinden çağrıldığı gibi davranmasını istiyorum.

Bunu nasıl yapabilirim veya bir komut dosyasını herhangi bir dizinden çalışacak şekilde nasıl değiştirebilirim?

Yanıtlar:


200

Komut dosyasının yanındaki bir dosyaya başvurabilmeniz için komut dosyasının kendi yolunu mu istiyorsunuz? Bunu dene:

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

$ MyInvocation ve özelliklerinden birçok bilgi edinebilirsiniz.

Geçerli çalışma dizinindeki bir dosyaya başvurmak istiyorsanız, Resolve-Path veya Get-ChildItem kullanabilirsiniz:

$filepath = Resolve-Path "somefile.txt"

EDIT (OP'nin yorumuna dayanarak):

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

# do stuff, call ant, etc

# now back to previous directory
Pop-Location

Invoke-Command kullanarak da benzer bir şey elde etmenin başka yolları da vardır.


1
Hmm, tamam, belki senaryom hakkında biraz daha net olmalıydım. Aslında antbazı parametrelerle çağıran bir betik . Bu yüzden antyapılandırma dosyasını doğru bulduğundan emin olmak için o klasörden aramam gerekiyor. İdeal olarak ben geçici olarak bu komut dosyası içinde yürütme dizini değiştirmek için bir şey arıyorum.
dürtmek

3
Ah o zaman bu durumda isteyeceksiniz Push-LocationvePop-Location
JohnL

5
dikkatli olun, $ MyInvocation bağlama duyarlıdır, genellikle $ ScriptPath = (Get-Variable MyInvocation -Scope Script) .Value.MyCommand.Path her türlü yuvalama veya işlevden çalışır

39

Yerel uygulamaları arıyorsanız, [Environment]::CurrentDirectoryPowerShell'in $PWDgeçerli dizini hakkında endişelenmeniz gerekir . Çeşitli nedenlerden dolayı, Set-Location veya Push-Location'ı seçtiğinizde PowerShell, işlemin geçerli çalışma dizinini ayarlamaz; bu nedenle, ayarlanmasını bekleyen uygulamalar (veya cmdlet'ler) çalıştırıyorsanız bunu yapmanız gerekir.

Bir komut dosyasında şunları yapabilirsiniz:

$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

Buna kusursuz bir alternatif yok. Birçoğumuz bilgi istemi fonksiyonumuza [Environment] :: CurrentDirectory öğesini ayarlamak için bir satır koyduk ... ancak bir betik içindeki konumu değiştirdiğinizde bu size yardımcı olmaz .

Bunun PowerShell tarafından otomatik olarak ayarlanmamasının nedeni hakkında iki not:

  1. PowerShell çok iş parçacıklı olabilir. Tek bir işlemde aynı anda çalışan birden çok Runspace (bkz. RunspacePool ve PSThreadJob modülü) olabilir. Her çalışma alanının kendi $PWDmevcut çalışma dizini vardır, ancak yalnızca bir işlem ve yalnızca bir Ortam vardır.
  2. Tek iş parçacıklı olsanız bile, $PWDher zaman yasal bir CurrentDirectory değildir (örneğin kayıt defteri sağlayıcısına CD yazabilirsiniz).

İsteminize koymak istiyorsanız (yalnızca ana çalışma alanında, tek iş parçacıklı çalışır), şunları kullanmanız gerekir:

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

4
Çünkü yol sağlayıcılarının süreci çalışma dizinini değişmez: Eğer kayıt, SQL veritabanı veya bir IIS kovanı vb cd'ing olabilir ...
piers7

1
Evet. Biliyorum, bu son "Son not" un amacı buydu. Onlar (benim istem işlevinde yaptığım gibi) dünyadaki diğer kabuk gibi FileSystem sağlayıcının geçerli konumuna güncelleştirmiş olabilir.
Jaykul

2
Kutsal yazı tanrıları, çok hayal kırıklığına uğradım .\_/.- çünkü bu günümün öldürülen yarısı için! İnsanlar, cidden mi? Cidden? ..
ulidtko

2
Artık çoğunlukla gereksizdir, PowerShell'in daha modern sürümleri ikili uygulamaları başlattıklarında çalışma dizinini ayarlar.
Jaykul

1
Bu yöntem [Environment]::CurrentDirectory, farklı olduğunda orijinalin geri yüklenmesinde başarısız olur $PWD. Yapılacak doğru şey bir değişkeni saklamak $origEnvDir = [Environment]::CurrentDirectoryve daha sonra geri yüklemek olacaktır [Environment]::CurrentDirectory = $origEnvDir.
Strom

37

Çok sayıda oy içeren cevaplar var, ancak sorunuzu okuduğumda, komut dosyasının çalıştığı dizini bilmek istediğinizi düşündüm. Powershell'in otomatik değişkenleri ile bilgi alabilirsiniz

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

Örneğin, ben visual studio çözüm dosyasını bulur ve başlatmak $ profil komut dosyası var. Bir çözüm dosyası başlatıldıktan sonra tam yolu saklamak istedim. Ama dosyayı orijinal betiğin bulunduğu yere kaydetmek istedim. Bu yüzden $ PsScriptRoot kullandım.


12

Sık sık çalışan kod ile aynı dizinin altında oturan bir modülü almak için aşağıdaki kodu kullandım. Önce powershell'in çalıştığı dizini alır

$ currentPath = Bölünmüş Yol ((Get-Değişken MyInvocation -Scope 0) .Value) .MyCommand.Path

import-module "$ currentPath \ sqlps.ps1"


-Scope'u Script olarak ayarlamak istiyorsunuz

9

Bu iyi olur.

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir

Pop-LocationYolu orijinal durumuna döndürmek için sonunda aramayı unutmayın .
Lam Le

2

Sadece bir süreliğine, sadece CLI'den herhangi bir komut dosyası olmadan bunun için bir çözüm arıyordum. Ben bunu nasıl xD:

  • Komut dosyasını çalıştırmak istediğiniz klasöre gidin (önemli olan sekme tamamlamaları olması)

    ..\..\dir

  • Şimdi konumu çift tırnak işaretleri içine alın ve bunların içine ekleyin cd, böylece başka bir powershell örneğini çağırabiliriz.

    "cd ..\..\dir"

  • İle ayrılmış komut dosyasını çalıştırmak için başka komut ekleme ;powershell komut ayırıcı olduğu ile,

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

  • Sonunda başka bir powershell örneği ile çalıştırın

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

Bu yeni powershell penceresi açar, pencereye gider ..\..\dir, çalıştırır script.ps1ve kapatır.


Bunu not et ";" komutları ayırır, tıpkı onları birer birer girdiğiniz gibi, ilk başarısız olursa ikinci çalışır ve sonraki ve sonraki sonraki ... Yeni powershell penceresini açık tutmak istiyorsanız -noexit'i iletin. Sekme tamamlamalarını kullanabilmem için önce istenen klasöre geçtiğimi unutmayın (çift tırnak işareti kullanamazsınız).

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

""Adlarında boşluk bulunan dizinleri aktarabilmek için çift ​​tırnak işareti kullanın , ör.

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


0

@ JohnL'nin çözümünden tek bir astar yaptım:

$MyInvocation.MyCommand.Path | Split-Path | Push-Location
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.