Jaki jest najlepszy sposób na określenie lokalizacji bieżącego skryptu PowerShell?

Gdy muszę odwołać się do wspólnego modułu lub skryptu, lubię używać ścieżek względem bieżącego pliku skryptu. W ten sposób mój skrypt zawsze może znaleźć Inne skrypty w bibliotece.

Jaki jest najlepszy, standardowy sposób określania katalogu bieżącego skryptu? Aktualnie robię:

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

I know in modules (.psm1) możesz użyć $PSScriptRoot, Aby uzyskać te informacje, ale nie jest to ustawiane w zwykłych skryptach (np. w plikach.ps1).

Co to jest kanoniczny sposób na uzyskanie lokalizacji aktualnego pliku skryptu PowerShell?

Author: Peter Mortensen, 2011-03-28

15 answers

PowerShell 3+

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

PowerShell 2

[[3]}przed PowerShell 3 nie było lepszego sposobu niż odpytywanie MyInvocation.MyCommand.Definition właściwość dla skryptów ogólnych. Miałem następujący wiersz na górze zasadniczo każdego skryptu PowerShell miałem:
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
 945
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-21 23:01:32

Jeśli tworzysz moduł V2, możesz użyć zmiennej automatycznej o nazwie $PSScriptRoot.

From PS > Help automatic_variable

$PSScriptRoot
       Contains the directory from which the script module is being executed.
       This variable allows scripts to use the module path to access other
       resources.
 64
Author: Andy Schneider,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-19 01:38:39

Dla 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.

Funkcja jest wtedy:

function Get-ScriptDirectory {
    Split-Path -Parent $PSCommandPath
}
 35
Author: CodeMonkeyKing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-19 01:39:34

Dla PowerShell 3 +

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

Umieściłem tę funkcję w moim profilu. Działa również w ISE przy użyciu F8/Run Selection.

 22
Author: nickkzl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-21 18:28:00

Może coś mi tu umyka... ale jeśli chcesz mieć obecny katalog roboczy, możesz po prostu użyć tego: (Get-Location).Path Dla ciągu znaków lub Get-Location dla obiektu.

Chyba, że mówisz o czymś takim, co rozumiem po ponownym przeczytaniu pytania.
function Get-Script-Directory
{
    $scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
    return Split-Path $scriptInvocation.MyCommand.Path
}
 17
Author: Sean C.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-21 23:00:39

Bardzo podobne do już zamieszczonych odpowiedzi, ale piping wydaje się bardziej podobny do PowerShella:

$PSCommandPath | Split-Path -Parent
 12
Author: CPAR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-21 18:28:26

Używam zmiennej automatycznej $ExecutionContext. Będzie działać z PowerShell 2 i Później.

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

$ExecutionContext Zawiera obiekt Engintrinsics, który reprezentuje kontekst wykonania hosta Windows PowerShell. Możesz użyj tej zmiennej, aby znaleźć obiekty wykonawcze, które są dostępne dla cmdletów.

 12
Author: Viggos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-29 09:10:00

Zajęło mi trochę czasu opracowanie czegoś, co przyjęło zaakceptowaną odpowiedź i przekształciło ją w solidną funkcję.

Nie jestem pewien co do innych, ale pracuję w środowisku z maszynami zarówno na PowerShell w wersji 2 jak i 3, więc musiałem obsługiwać oba. Następująca funkcja oferuje graceful 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
}

Oznacza to również, że funkcja odnosi się do zakresu skryptu, a nie do zakresu rodzica, jak opisał Michael Sorens w jednym z jego postów na blogu .

 10
Author: Bruno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-21 18:30:03

Musiałem znać nazwę skryptu i skąd jest wykonywany.

Prefiks "$global: "do struktury MyInvocation zwraca pełną ścieżkę i nazwę skryptu, gdy jest wywoływany zarówno ze skryptu głównego, jak i z importowanej linii .Plik biblioteki PSM1. Działa również z poziomu funkcji zaimportowanej biblioteki.

Po długim grzebieniu, zdecydowałem się na użycie $global: MyInvocation.InvocationName. Działa niezawodnie z CMD launch, Uruchom z Powershell i ISE. Obie local and UNC launches return the correct path.

 7
Author: Bruce Gavin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-12 22:21:24

Zawsze używam tego małego fragmentu, który działa na PowerShell i ISE w ten sam sposób:

# 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
Author: Peter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-21 18:07:03

Odkryłem, że starsze rozwiązania opublikowane tutaj nie działają dla mnie na PowerShell V5. Wymyśliłem to:

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"
 3
Author: Quantium,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-21 18:26:32

Wykorzystując fragmenty z tych wszystkich odpowiedzi i komentarzy, składam to razem dla każdego, kto widzi to pytanie w przyszłości. Obejmuje wszystkie sytuacje wymienione w pozostałych odpowiedziach

    # If using ISE
    if ($psISE) {
        $ScriptPath = Split-Path -Parent $psISE.CurrentFile.FullPath
    # If Using PowerShell 3 or greater
    } elseif($PSVersionTable.PSVersion.Major -gt 3) {
        $ScriptPath = $PSScriptRoot
    # If using PowerShell 2 or lower
    } else {
        $ScriptPath = split-path -parent $MyInvocation.MyCommand.Path
    }

 3
Author: Randy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-09 16:24:17

Możesz również rozważyć split-path -parent $psISE.CurrentFile.Fullpath, jeśli którakolwiek z innych metod zawodzi. W szczególności, jeśli uruchomisz plik, aby załadować kilka funkcji, a następnie wykonasz te funkcje z-w powłoce ISE (lub jeśli uruchomisz-zaznaczone), wygląda na to, że funkcja Get-Script-Directory Jak powyżej nie działa.

 2
Author: fastboxster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-29 21:44:53

Jeśli chcesz załadować moduły ze ścieżki w stosunku do miejsca uruchomienia skryptu, na przykład z podfolderu "lib", musisz użyć jednej z następujących opcji:

$PSScriptRoot który działa, gdy jest wywoływany jako skrypt, na przykład za pomocą polecenia PowerShell $psISE.CurrentFile.FullPath który działa, gdy biegasz wewnątrz ISE

Ale jeśli nie jesteś w żadnej z nich i po prostu piszesz w PowerShell shell, możesz użyć:

pwd.Path

Można przypisać jedną z trzech do zmiennej o nazwie $base w zależności od environment you ' re running under, like so:

$base=$(if ($psISE) {Split-Path -Path $psISE.CurrentFile.FullPath} else {$(if ($global:PSScriptRoot.Length -gt 0) {$global:PSScriptRoot} else {$global:pwd.Path})})

Następnie w skryptach możesz go używać w następujący sposób:

Import-Module $base\lib\someConstants.psm1
Import-Module $base\lib\myCoolPsModule1.psm1
#etc.
 0
Author: zumalifeguard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-09 22:39:31
function func1() 
{
   $inv = (Get-Variable MyInvocation -Scope 1).Value
   #$inv.MyCommand | Format-List *   
   $Path1 = Split-Path $inv.scriptname
   Write-Host $Path1
}

function Main()
{
    func1
}

Main
 -4
Author: Ravi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-28 07:47:34