wake-up-neo.com

Wie kann der Speicherort des aktuellen PowerShell-Skripts am besten ermittelt werden?

Wenn ich auf ein allgemeines Modul oder Skript verweisen muss, verwende ich gerne Pfade relativ zur aktuellen Skriptdatei. Auf diese Weise kann mein Skript immer andere Skripts in der Bibliothek finden.

Was ist also die beste Standardmethode zum Ermitteln des Verzeichnisses des aktuellen Skripts? Derzeit mache ich:

$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)

Ich weiß, dass Sie in Modulen (.psm1) $PSScriptRoot verwenden können, um diese Informationen abzurufen, aber dies wird in regulären Skripten (d. H. .Ps1-Dateien) nicht festgelegt.

Wie kann man auf kanonische Weise den Speicherort der aktuellen PowerShell-Skriptdatei ermitteln?

470
Aaron Jensen

PowerShell 3 +

# This is an automatic variable set to the current file's/module's directory
$PSScriptRoot

PowerShell 2

Vor PowerShell 3 gab es keinen besseren Weg, als die Eigenschaft MyInvocation.MyCommand.Definition nach allgemeinen Skripten abzufragen. Ich hatte die folgende Zeile oben in praktisch jedem Powershell-Skript, das ich hatte:

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
767
JaredPar

Wenn Sie ein V2-Modul erstellen, können Sie eine automatische Variable namens $PSScriptRoot verwenden.

Von PS> Hilfe automatic_variable

 $ PSScriptRoot 
 Enthält das Verzeichnis, aus dem das Skriptmodul ausgeführt wird. 
 Mit dieser Variablen können Skripte über den Modulpfad auf andere 
 Ressourcen zugreifen. 
59
Andy Schneider

Für PowerShell 3.0

$PSCommandPath
    Contains the full path and file name of the script that is being run. 
    This variable is valid in all scripts.

Die Funktion ist dann:

function Get-ScriptDirectory {
    Split-Path -Parent $PSCommandPath
}
30
CodeMonkeyKing

Vielleicht fehlt mir hier etwas ... aber wenn Sie das aktuelle Arbeitsverzeichnis haben möchten, können Sie dies einfach verwenden: (Get-Location).Path für einen String oder Get-Location für ein Objekt.

Es sei denn, Sie beziehen sich auf so etwas, was ich verstehe, nachdem ich die Frage noch einmal gelesen habe.

function Get-Script-Directory
{
    $scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
    return Split-Path $scriptInvocation.MyCommand.Path
}
14
Sean C.

Für Powershell 3+

function Get-ScriptDirectory {
    if ($psise) {Split-Path $psise.CurrentFile.FullPath}
    else {$global:PSScriptRoot}
}

Ich habe diese Funktion in mein Profil aufgenommen. Funktioniert in ISE auch mit F8/Run Selection.

14
nickkzl

Sehr ähnlich zu bereits geposteten Antworten, aber das Piping scheint eher PS-artig zu sein.

$PSCommandPath | Split-Path -Parent
11
CPAR

Ich verwende die automatische Variable $ ExecutionContext, sie funktioniert ab PowerShell 2 und höher.

$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\')

$ ExecutionContext Enthält ein EngineIntrinsics-Objekt, das den Ausführungskontext des Windows PowerShell-Hosts darstellt. Mit dieser Variablen können Sie die Ausführungsobjekte suchen, die für Cmdlets verfügbar sind.

10
Viggos

Ich musste den Namen des Skripts kennen und wissen, von wo es ausgeführt wird.

Das Präfix "$ global:" in der MyInvocation-Struktur gibt den vollständigen Pfad und den Skriptnamen zurück, wenn sie sowohl vom Hauptskript als auch von der Hauptzeile einer importierten PSM1-Bibliotheksdatei aufgerufen werden. Es funktioniert auch innerhalb einer Funktion in einer importierten Bibliothek.

Nachdem ich viel herumgespielt hatte, entschied ich mich für $ global: MyInvocation.InvocationName. Es funktioniert zuverlässig mit CMD-Start, Run With Powershell und ISE. Sowohl lokale als auch UNC-Starts geben den richtigen Pfad zurück.

7
Bruce Gavin

Ich habe eine Weile gebraucht, um etwas zu entwickeln, das die akzeptierte Antwort aufgegriffen und in eine robuste Funktion umgewandelt hat.

Ich bin mir anderer nicht sicher, arbeite aber in einer Umgebung mit Computern in PowerShell Version 2 und 3, sodass ich mit beiden umgehen musste. Die folgende Funktion bietet einen angemessenen Fallback:

Function Get-PSScriptRoot
{
    $ScriptRoot = ""

    Try
    {
        $ScriptRoot = Get-Variable -Name PSScriptRoot -ValueOnly -ErrorAction Stop
    }
    Catch
    {
        $ScriptRoot = Split-Path $script:MyInvocation.MyCommand.Path
    }

    Write-Output $ScriptRoot
}

Dies bedeutet auch, dass sich die Funktion auf den Gültigkeitsbereich des Skripts bezieht und nicht auf den Gültigkeitsbereich des übergeordneten Elements, wie von Michael Sorens in seinem Blog beschrieben

7
Bruno

Ich benutze immer dieses kleine Snippet, das für Powershell und ISE genauso funktioniert:

# set active path to script-location:
$path = $MyInvocation.MyCommand.Path
if (!$path) {$path = $psISE.CurrentFile.Fullpath}
if ( $path) {$path = split-path $path -Parent}
set-location $path
5
Peter

Sie können auch split-path -parent $psISE.CurrentFile.Fullpath in Betracht ziehen, wenn eine der anderen Methoden fehlschlägt. Insbesondere wenn Sie eine Datei ausführen, um eine Reihe von Funktionen zu laden, und diese Funktionen dann in der ISE-Shell ausführen (oder wenn Sie sie ausgewählt haben), scheint die Funktion Get-Script-Directory wie oben nicht zu funktionieren.

2
user2023266

Es wurde festgestellt, dass die hier veröffentlichten älteren Lösungen für PowerShell V5 nicht funktionieren. Das habe ich mir ausgedacht:

try {
    $scriptPath = $PSScriptRoot
    if (!$scriptPath)
    {
        if ($psISE)
        {
            $scriptPath = Split-Path -Parent -Path $psISE.CurrentFile.FullPath
        } else {
            Write-Host -ForegroundColor Red "Cannot resolve script file's path"
            exit 1
        }
    }
} catch {
    Write-Host -ForegroundColor Red "Caught Exception: $($Error[0].Exception.Message)"
    exit 2
}

Write-Host "Path: $scriptPath"

HTH

2
Quantium