So rufen Sie das aktuelle Verzeichnis des ausgeführten Cmdlets ab

202

Dies sollte eine einfache Aufgabe sein, aber ich habe mehrere Versuche gesehen, wie der Pfad zu dem Verzeichnis, in dem sich das ausgeführte Cmdlet befindet, mit gemischtem Erfolg abgerufen werden kann. Wenn ich zum Beispiel C:\temp\myscripts\mycmdlet.ps1eine Einstellungsdatei bei ausführe , C:\temp\myscripts\settings.xmlmöchte ich in der Lage sein, C:\temp\myscriptsin einer Variablen darin zu speichern mycmdlet.ps1.

Dies ist eine Lösung, die funktioniert (obwohl etwas umständlich):

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

Ein anderer schlug diese Lösung vor, die nur in unserer Testumgebung funktioniert:

$settingspath = '.\settings.xml'

Ich mag den letzteren Ansatz sehr und ziehe es vor, den Dateipfad jedes Mal als Parameter analysieren zu müssen, aber ich kann ihn nicht in meiner Entwicklungsumgebung zum Laufen bringen. Was soll ich tun? Hat dies etwas mit der Konfiguration von PowerShell zu tun?

Stig Perez
quelle
11
Beachten Sie, dass der mehrdeutige Titel dieser Frage dazu geführt hat, dass die folgenden Antworten eines von zwei unterschiedlichen Problemen lösen, ohne explizit anzugeben, welche: (a) wie auf den aktuellen Speicherort (Verzeichnis) verwiesen wird oder (b) wie auf den Speicherort des laufenden Skripts verwiesen wird ( das Verzeichnis, in dem sich das laufende Skript befindet (möglicherweise das aktuelle Verzeichnis).
mklement0

Antworten:

143

Der zuverlässige Weg, dies zu tun, ist genau so, wie Sie es gezeigt haben $MyInvocation.MyCommand.Path.

Die Verwendung relativer Pfade basiert auf $ pwd in PowerShell, dem aktuellen Verzeichnis für eine Anwendung oder dem aktuellen Arbeitsverzeichnis für eine .NET-API.

PowerShell v3 + :

Verwenden Sie die automatische Variable $PSScriptRoot.

JasonMArcher
quelle
6
Können Sie mir bitte erklären, wie Sie die Immobilie PATH gefunden haben? $ MyInvocation.MyCommand | gm zeigt eine solche Eigenschaft nicht in der Mitgliederliste an.
Vitaliy Markitanov
19
Warum nicht einfach $ PSScriptRoot verwenden? Scheint zuverlässiger
mBrice1024
@ user2326106 Kannst du den Unterschied zwischen $PSScriptRootund erklären $MyInvocation.MyCommand.Path?
duct_tape_coder
1
Diese Antwort ist unvollständig.
K - Die Toxizität in SO nimmt zu.
Diese Antwort ist unvollständig.
Stackleit
263

Ja, das sollte funktionieren. Aber wenn Sie den absoluten Pfad sehen müssen, ist dies alles, was Sie brauchen:

(Get-Item -Path ".\").FullName
GuruKay
quelle
4
Vielen Dank, dies ist eine großartige Methode, um den vollständigen Pfad von relativen Pfaden zu finden. ZB (Get-Item -Path $ myRelativePath -Verbose) .FullName
dlux
Danke dafür. Andere Antworten funktionierten nicht für Powershell-Skripte, die zu EXEs kompiliert wurden.
Zach Alexander
10
Das ist falsch . Dadurch wird das aktuelle Verzeichnis des Prozesses abgerufen , das sich an einer beliebigen Stelle befinden kann. Wenn sich beispielsweise mein aktuelles Befehlszeilenverzeichnis befindet C:\mydirund ich den Befehl aufrufe C:\dir1\dir2\dir3\mycmdlet.ps1, wird dies in C:\mydirnicht aufgelöst C:\dir1\dir2\dir3. Das Aufrufen einer neuen ausführbaren Datei hat das gleiche Problem, da das aktuelle Verzeichnis vom übergeordneten Prozess geerbt wird.
jpmc26
85

Die einfachste Methode scheint darin zu bestehen, die folgende vordefinierte Variable zu verwenden:

 $PSScriptRoot

about_Automatic_Variablesund about_Scriptsbeide geben an:

In PowerShell 2.0 ist diese Variable nur in Skriptmodulen (.psm1) gültig. Ab PowerShell 3.0 ist es in allen Skripten gültig.

Ich benutze es so:

 $MyFileName = "data.txt"
 $filebase = Join-Path $PSScriptRoot $MyFileName
Tony Sheen
quelle
12
Es ist versionenspezifisch. Dies erfordert mindestens Powershell 3.0.
Marvin Dickhaus
1
Dies ist, was ich brauchte, um auf eine Datei am selben Speicherort wie das Skript zu verweisen - danke!
Adam Prescott
Dies ist die beste Antwort, da Sie genau den Pfad angeben, in dem Ihr PS-Skript vorhanden ist. Dies ist im Wesentlichen die Wurzel für Ihre Skriptausführung. Es ist egal, in welchem ​​aktuellen Arbeitsverzeichnis Sie Ihre Skripte aufgerufen haben. +1.
RBT
@MarvinDickhaus Deshalb muss in den meisten Skripten "Set-StrictMode -Version 3.0" verwendet werden :) Vielen Dank für die Links!
Alexander Shapkin
44

Sie können auch verwenden:

(Resolve-Path .\).Path

Der Teil in Klammern gibt ein PathInfoObjekt zurück.

(Verfügbar seit PowerShell 2.0.)

Alex Angas
quelle
2
Das ist falsch . Dadurch wird das aktuelle Verzeichnis des Prozesses abgerufen , das sich an einer beliebigen Stelle befinden kann. Wenn sich beispielsweise mein aktuelles Befehlszeilenverzeichnis befindet C:\mydirund ich den Befehl aufrufe C:\dir1\dir2\dir3\mycmdlet.ps1, wird dies in C:\mydirnicht aufgelöst C:\dir1\dir2\dir3. Das Aufrufen einer neuen ausführbaren Datei hat das gleiche Problem, da das aktuelle Verzeichnis vom übergeordneten Prozess geerbt wird.
jpmc26
3
Vielen Dank! Ich habe auch den Titel dieser Frage falsch verstanden, und diese Antwort war genau das, wonach ich gesucht habe. Allerdings ... Es beantwortet die Frage nicht.
Ryan The Leach
33

Pfad ist oft null. Diese Funktion ist sicherer.

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("\"));
    }
}
Christian Flem
quelle
1
warum - Bereich 1? not -Scope 0
suiwenfeng
1
Get-Variable: Die Bereichsnummer '1' überschreitet die Anzahl der aktiven Bereiche.
Suiwenfeng
2
Sie erhalten diesen Fehler, weil Sie keinen übergeordneten Bereich haben. Der Parameter -Scope ruft die Variable in einem angegebenen Bereich ab. 1 ist in diesem Fall der übergeordnete Bereich. Weitere Informationen finden Sie in diesem Technet-Artikel über Get-Variable ( technet.microsoft.com/en-us/library/hh849899.aspx )
Christian Flem
27

Versuchen :

(Get-Location).path

oder:

($pwd).path
Rohin Sidharth
quelle
Ich vergesse immer wieder , über $pwd/ $PWDwenn ich eine lange Pause von Powershell nehmen! So viel nützlicher IMO ...
kayleeFrye_onDeck
17

Get-Location gibt den aktuellen Speicherort zurück:

$Currentlocation = Get-Location
Veera Induvasi
quelle
3
PS C: \ Windows \ system32> C: \ Powershell \ checkfile.ps1 -> dies gibt c: \ windows \ system32
nbi
11

Ich mag die einzeilige Lösung :)

$scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
FrankyHollywood
quelle
Dies ist die bisher beste Lösung.
Teoman Shipahi
Ja funktioniert bei mir. Mein pwd ist mein Benutzerverzeichnis und ich
führe
8

Versuche dies:

$WorkingDir = Convert-Path .
Siebenfacher Exurbanit
quelle
4

In Powershell 3 und höher können Sie einfach verwenden

$PSScriptRoot

BlackSpy
quelle
1

Sie würden denken, dass die Verwendung von '. \' Als Pfad bedeutet, dass es sich um den Aufrufpfad handelt. Aber nicht die ganze Zeit. Beispiel, wenn Sie es in einem Job ScriptBlock verwenden. In diesem Fall kann es auf% profile% \ Documents verweisen.

Syanzy
quelle
1

Diese Funktion setzt den Ort der Eingabeaufforderung auf den Skriptpfad und behandelt die unterschiedlichen Methoden zum Abrufen des Skriptpfads zwischen vscode, psise und 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 }
}
freakydinde
quelle
0

Für das, was es wert ist, eine einzeilige Lösung zu sein, ist das Folgende eine funktionierende Lösung für mich.

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

Die 1 am Ende ist das zu ignorieren / .

Dank der obigen Beiträge mit dem Cmdlet Get-Location .

Ak777
quelle
0

Die meisten Antworten funktionieren beim Debuggen in den folgenden IDEs nicht:

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

Denn in denen $PSScriptRootist das leer undResolve-Path .\ (und Ähnliches) führt zu falschen Pfaden.

Die Antwort von Freakydinde ist die einzige, die diese Situationen löst, also habe ich das hochgestimmt , aber ich denke nicht, Set-Locationdass die Antwort wirklich das ist, was gewünscht wird. Also habe ich das behoben und den Code etwas klarer gemacht:

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

Um die Antwort von @Cradle zu erweitern: Sie können auch eine Mehrzweckfunktion schreiben , mit der Sie das gleiche Ergebnis gemäß der Frage des OP erzielen :

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
    }

}
Erutan409
quelle
-1

Wenn Sie nur den Namen des aktuellen Verzeichnisses benötigen, können Sie Folgendes tun:

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

Angenommen, Sie arbeiten in C: \ Temp \ Location \ MyWorkingDirectory>

Ausgabe

MyWorkingDirectory

SolThoth
quelle
-1

Ich hatte ähnliche Probleme und es machte mir große Probleme, da ich in PowerShell geschriebene Programme (GUI-Anwendungen für Endbenutzer) erstelle und viele Dateien und Ressourcen habe, die ich von der Festplatte laden muss. Aus meiner Erfahrung mit . Danach wechselt PowerShell das Verzeichnis entweder in das Verzeichnis, aus dem Sie es aufgerufen haben, oder in das Verzeichnis, in dem sich das von Ihnen ausgeführte Skript befindet, bevor Sie entweder die PowerShell-Eingabeaufforderung erhalten oder das Skript ausführen. Dies geschieht jedoch, nachdem die PowerShell-App ursprünglich in Ihrem privaten Benutzerverzeichnis gestartet wurde.. zur Darstellung des aktuellen Verzeichnisses unzuverlässig. Es sollte das aktuelle Arbeitsverzeichnis darstellen, ist es aber häufig nicht. Es scheint, dass PowerShell den Speicherort speichert, von dem aus PowerShell aufgerufen wurde .. Genauer gesagt wird PowerShell beim ersten Start standardmäßig in Ihrem Home-Benutzerverzeichnis gestartet. Das ist normalerweise das Verzeichnis Ihres BenutzerkontosC:\USERS\YOUR USER NAME

Und .repräsentiert das ursprüngliche Verzeichnis, in dem PowerShell gestartet wurde. Stellt also .nur das aktuelle Verzeichnis dar, wenn Sie PowerShell aus dem gewünschten Verzeichnis aufgerufen haben. Wenn Sie später das Verzeichnis im PowerShell-Code ändern, scheint sich die Änderung nicht .in jedem Fall darin zu widerspiegeln . In einigen Fällen handelt es sich .um das aktuelle Arbeitsverzeichnis, in anderen um das Verzeichnis, aus dem PowerShell (selbst, nicht das Skript) aufgerufen wurde, was zu inkonsistenten Ergebnissen führen kann. Aus diesem Grund verwende ich ein Invoker-Skript. PowerShell-Skript mit einem einzigen Befehl : POWERSHELL. Dadurch wird sichergestellt, dass PowerShell aus dem gewünschten Verzeichnis aufgerufen wird und somit make.aktuelles Verzeichnis darstellen. Dies funktioniert jedoch nur, wenn Sie das Verzeichnis später im PowerShell-Code nicht ändern. Im Falle eines Skripts verwende ich ein Aufruferskript, das dem zuletzt erwähnten ähnlich ist, außer dass es eine Dateioption enthält : POWERSHELL -FILE DRIVE:\PATH\SCRIPT NAME.PS1. Dadurch wird sichergestellt, dass PowerShell im aktuellen Arbeitsverzeichnis gestartet wird.

Durch einfaches Klicken auf das Skript wird PowerShell aus Ihrem privaten Benutzerverzeichnis aufgerufen, unabhängig davon, wo sich das Skript befindet. Dies führt dazu, dass das aktuelle Arbeitsverzeichnis das Verzeichnis ist, in dem sich das Skript befindet, das PowerShell-Aufrufverzeichnis jedoch C:\USERS\YOUR USER NAME, und dass .je nach Situation eines dieser beiden Verzeichnisse zurückgegeben wird, was lächerlich ist.

Um all diese Aufregung zu vermeiden und das Aufruferskript zu verwenden, können Sie einfach entweder $PWDoder $PSSCRIPTROOTanstelle des .aktuellen Verzeichnisses verwenden, je nachdem, ob Sie das aktuelle Arbeitsverzeichnis oder das Verzeichnis darstellen möchten, aus dem das Skript aufgerufen wurde. Und wenn Sie aus irgendeinem Grund ein anderes von zwei zurückgegebenen Verzeichnissen abrufen möchten ., können Sie verwenden $HOME.

Ich persönlich habe nur ein Aufruferskript im Stammverzeichnis meiner Apps, die ich mit PowerShell entwickelt habe und das mein Haupt-App-Skript aufruft, und denke einfach daran, niemals das aktuelle Arbeitsverzeichnis in meinem Quellcode meiner App zu ändern, damit ich mir darüber keine Sorgen machen muss. und ich kann verwenden ., um das aktuelle Verzeichnis darzustellen und die relative Dateiadressierung in meinen Anwendungen ohne Probleme zu unterstützen. Dies sollte in neueren Versionen von PowerShell (neuer als Version 2) funktionieren.

SYOB SYOT
quelle