Yürütülen cmdlet'in geçerli dizinini alma


203

Bu basit bir görev olmalı, ancak çalıştırılan cmdlet'in karışık başarı ile bulunduğu dizine giden yolun nasıl elde edileceği konusunda birkaç girişim gördüm. Örneğin C:\temp\myscripts\mycmdlet.ps1, bir ayar dosyası olan yürüttüğümde içindeki bir değişkende C:\temp\myscripts\settings.xmlsaklamak istiyorum .C:\temp\myscriptsmycmdlet.ps1

Bu, işe yarayan bir çözümdür (biraz hantal olsa da):

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

Bir diğeri, sadece test ortamımızda çalışan bu çözümü önerdi:

$settingspath = '.\settings.xml'

İkinci yaklaşımı çok seviyorum ve her seferinde dosyayolunu bir parametre olarak ayrıştırmayı tercih ediyorum, ancak geliştirme ortamımda çalışamıyorum. Ne yapmalıyım? PowerShell'in yapılandırılmasıyla bir ilgisi var mı?


11
Bu sorunun belirsiz başlık açıkça belirtmeden, iki ayrı sorunlarından birini çözmeye aşağıdaki yanıtları neden olduğunu Not: (a) başvuru nasıl geçerli konumunu (dizin) veya başvuru nasıl (b) çalıştıran komut dosyasının konumunu ( çalışmakta olan komut dosyasının bulunduğu dizin (geçerli dizin olabilir veya olmayabilir)).
mklement0

Yanıtlar:


145

Bunu yapmanın güvenilir yolu tıpkı gösterdiğin gibi $MyInvocation.MyCommand.Path.

Göreli yolları kullanmak $ pwd, PowerShell, bir uygulamanın geçerli dizini veya bir .NET API'nin geçerli çalışma dizinini temel alır.

PowerShell v3 + :

Otomatik değişkeni kullanın $PSScriptRoot.


6
Lütfen bana PATH mülkünü nasıl bulduğunu açıklayabilir misin? $ MyInvocation.MyCommand | gm üye listesinde böyle bir özellik göstermez.
Vitaliy Markitanov

19
neden sadece $ PSScriptRoot kullanmıyorsunuz? Daha güvenilir görünüyor
mBrice1024

@ user2326106 $PSScriptRootve arasındaki farkı açıklayabilir misiniz $MyInvocation.MyCommand.Path?
duct_tape_coder

1
Bu cevap eksik.
K - SO'da toksisite artıyor.

Bu cevap eksik.
19:55

263

Evet, işe yaramalı. Ancak mutlak yolu görmeniz gerekiyorsa, ihtiyacınız olan tek şey budur:

(Get-Item .).FullName

4
Teşekkürler, göreceli yollardan tam yolu bulmak için harika bir yöntemdir. Örneğin (Al-Item -Path $ myRelativePath -Verbose) .FullName
DLUX

Bunun için teşekkür ederim. Diğer yanıtlar EXE'lere derlenen Powershell komut dosyaları için çalışmadı.
Zach Alexander

10
Bu yanlış . Bu, işlemin herhangi bir yerde olabilen geçerli dizinini alır . Örneğin, komut satırı geçerli C:\mydirdizinim ve komutu çağırırsam, C:\dir1\dir2\dir3\mycmdlet.ps1bu çözülmez C:\mydir, değil C:\dir1\dir2\dir3. Geçerli dizin üst işlemden devralındığından, yeni bir yürütülebilir dosyayı çağırmak aynı soruna sahiptir.
jpmc26

85

En kolay yöntem, aşağıdaki önceden tanımlanmış değişkeni kullanmak gibi görünüyor:

 $PSScriptRoot

about_Automatic_Variablesve about_Scriptsher ikisi de:

PowerShell 2.0'da, bu değişken yalnızca komut dosyası modüllerinde (.psm1) geçerlidir. PowerShell 3.0'dan başlayarak, tüm komut dosyalarında geçerlidir.

Ben böyle kullanın:

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

12
Sürüme özgüdür. Bu en azından Powershell 3.0 gerektirir.
Marvin Dickhaus

1
Komut dosyası ile aynı konumda bir dosyaya başvurmak için ihtiyacım olan şey bu - teşekkürler!
Adam Prescott

Bu size en iyi cevaptır, çünkü tam olarak betik yürütmenizin kökü olan PS betiğinizin bulunduğu yolu verir. Komut dosyalarınızı çağırdığınız yerden şu andaki çalışma dizininizin ne olduğu önemli değildir. +1.
RBT

@MarvinDickhaus Bu yüzden çoğu komut dosyasında "Set-StrictMode -Version 3.0" kullanılması gerekiyor :) Bağlantılar için büyük teşekkürler!
Alexander Shapkin

44

Ayrıca kullanabilirsiniz:

(Resolve-Path .\).Path

Köşeli parantez içindeki parça bir PathInfonesne döndürür .

(PowerShell 2.0'dan beri kullanılabilir.)


2
Bu yanlış . Bu, işlemin herhangi bir yerde olabilen geçerli dizinini alır . Örneğin, komut satırı geçerli C:\mydirdizinim ve komutu çağırırsam, C:\dir1\dir2\dir3\mycmdlet.ps1bu çözülmez C:\mydir, değil C:\dir1\dir2\dir3. Geçerli dizin üst işlemden devralındığından, yeni bir yürütülebilir dosyayı çağırmak aynı soruna sahiptir.
jpmc26

3
Teşekkürler! Bu sorunun başlığını da yanlış anladım ve bu cevap tam da aradığım şeydi. Ancak ... Bu soruya cevap vermiyor.
Ryan The Leach

33

Yol genellikle boştur. Bu işlev daha güvenlidir.

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
neden -Scope 1? değil -Scope 0
suiwenfeng

1
Değişken Olsun: '1' kapsam numarası etkin kapsam sayısını aşıyor.
suiwenfeng

2
Üst alanınız olmadığı için bu hatayı alıyorsunuz. -Scope parametresi değişkeni belirtilen kapsamda alır. Bu durumda 1, ana kapsamdır. Daha fazla bilgi için Get-DeğiĢkenine bu technet makaleye (bkz technet.microsoft.com/en-us/library/hh849899.aspx )
Christian Flem


17

Get-Location geçerli konumu döndürür:

$Currentlocation = Get-Location

4
PS C: \ Windows \ system32> C: \ powershell \ checkfile.ps1 -> bu c: \ windows \ system32
nbi



4

Powershell 3 ve üzeri sürümlerde şunları kullanabilirsiniz:

$PSScriptRoot


2

Bu işlev komut istemi konumunu komut dosyası yoluna ayarlayarak vscode, psise ve pwd arasındaki komut dosyası yolunu almanın farklı yolunu ele alır:

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 }
}

2

Çoğu yanıt aşağıdaki IDE'lerde hata ayıklama sırasında çalışmaz:

  • PS-ISE (PowerShell ISE)
  • VS Kodu (Visual Studio Kodu)

Çünkü bunlar $PSScriptRootboş ve Resolve-Path .\(ve benzerleri) yanlış yollara yol açacaktır.

Freakydinde'nin cevabı , bu durumları çözen tek cevaptır , bu yüzden buna oy verdim, ancak Set-Locationbu cevapta gerçekten istenen şey olduğunu düşünmüyorum . Bu yüzden bunu düzelttim ve kodu biraz daha net hale getirdim:

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

1

Yol olarak '. \' Kullanmanın çağırma yolu olduğu anlamına gelir. Fakat her zaman değil. Örneğin, bir ScriptBlock işinde kullanırsanız. Bu durumda% profile% \ Documents öğesini gösterebilir.


0

Sadece geçerli dizinin adına ihtiyacınız varsa, böyle bir şey yapabilirsiniz:

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

C: \ Temp \ Location \ MyWorkingDirectory> adresinden çalıştığınızı varsayarsak>

Çıktı

MyWorkingDirectory


Neden birilerinin bunu oylamadığından emin değil misiniz? Gördüğüm en temiz çözüm.
Tomas Jansson

0

Değeri için, tek satırlık bir çözüm olmak, aşağıda benim için çalışan bir çözüm.

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

Sondaki 1 /.

Get-Location cmdlet'ini kullanarak yukarıdaki yayınlar sayesinde .


-1

@Cradle'ın cevabını genişletmek için: OP'nin sorusu başına aynı sonucu elde etmenizi sağlayacak çok amaçlı bir işlev de yazabilirsiniz :

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

Benzer sorunları yaşadım ve PowerShell'de (tam son kullanıcı GUI uygulamaları) yazılmış programlar yaptığım ve diskten yüklemem gereken çok fazla dosya ve kaynak var. Deneyimlerime göre, .geçerli dizini temsil etmek için kullanmak güvenilmez. Geçerli çalışma dizinini temsil etmelidir, ancak genellikle göstermez. PowerShell'in, PowerShell'in içinden çağrıldığı konumu kaydettiği anlaşılıyor .. Daha kesin olmak gerekirse, PowerShell ilk başlatıldığında, varsayılan olarak ana kullanıcı dizininizde başlar. Bu genellikle kullanıcı hesabınızın dizinidir.C:\USERS\YOUR USER NAME. Bundan sonra, PowerShell, ya PowerShell istemini sunmadan ya da komut dosyasını çalıştırmadan önce dizini ya çağırdığınız dizine ya da yürüttüğünüz komut dosyasının bulunduğu dizine değiştirir. Ancak bu, PowerShell uygulamasının kendisi başlangıçta ev kullanıcı dizininizde başladıktan sonra olur.

Ve .PowerShell başladığı ilk dizin içini temsil eder. Dolayısıyla ., PowerShell'i istenen dizinden çağırdıysanız yalnızca geçerli dizini temsil eder. Daha sonra PowerShell kodunda dizini değiştirirseniz, değişiklik .her durumda içeriye yansıtılmamış gibi görünür . Bazı durumlarda .geçerli çalışma dizinini ve PowerShell'in (komut dosyası değil, kendisinin çağrıldığı) diğer dizinlerde tutarsız sonuçlara yol açabilir. Bu nedenle invoker betiği kullanıyorum. Tek komut içiyle PowerShell komut dosyası: POWERSHELL. Bu, PowerShell'in istenen dizinden çağrılmasını sağlar ve böylece. geçerli dizini temsil eder. Ancak, dizini daha sonra PowerShell kodunda değiştirmezseniz çalışır. Bir komut dosyası durumunda, bir dosya seçeneği içermesi dışında, bahsettiğim sonuncuya benzer invoker komut dosyası kullanıyorum: POWERSHELL -FILE DRIVE:\PATH\SCRIPT NAME.PS1 . Bu, PowerShell'in geçerli çalışma dizini içinde başlatılmasını sağlar.

Betiğe tıklamak, betiğin bulunduğu konum ne olursa olsun ana kullanıcı dizininizden PowerShell'i çağırır. Bu senaryo bulunduğu Geçerli çalışma dizini olmak dizin olan sonuç, ancak PowerShell çağırma dizin varlık C:\USERS\YOUR USER NAMEve birlikte .duruma göre, bu iki dizinlerden birini dönen, saçma şeydir.

Ancak tüm bu yaygarayı önlemek ve invoker komut dosyasını kullanmak için, geçerli çalışma dizinini veya komut dosyasının çağrıldığı dizini temsil etmek istediğiniz hava durumuna bağlı olarak geçerli dizini temsil etmek için $PWDveya $PSSCRIPTROOTyerine kullanabilirsiniz .. Ve herhangi bir nedenle, .geri dönen iki dizinden diğerini almak istiyorsanız, kullanabilirsiniz $HOME.

Kişisel olarak sadece ana uygulama komut dizimi çağıran PowerShell ile geliştirdiğim uygulamalarımın kök dizini içinde invoker betiğim var ve basitçe, uygulamanızın kaynak kodundaki geçerli çalışma dizinini hiçbir zaman değiştirmemeyi hatırlıyorum, bu yüzden asla endişelenmem, ve .geçerli dizini temsil etmek ve uygulamalarımda göreceli dosya adreslemeyi sorunsuz bir şekilde desteklemek için kullanabilirim . Bu, PowerShell'in daha yeni sürümlerinde (sürüm 2'den daha yeni) çalışmalıdır.

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.