web-dev-qa-db-fra.com

Quelle est la meilleure façon de déterminer l'emplacement du script PowerShell actuel?

Chaque fois que je dois référencer un module ou un script commun, j'aime utiliser des chemins relatifs au fichier de script actuel. Ainsi, mon script peut toujours rechercher d'autres scripts dans la bibliothèque.

Alors, quel est le meilleur moyen standard de déterminer le répertoire du script actuel? Actuellement, je fais:

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

Je sais que dans les modules (.psm1), vous pouvez utiliser $PSScriptRoot pour obtenir ces informations, mais cela n’est pas défini dans les scripts classiques (fichiers .ps1).

Quel est le moyen canonique d’obtenir l’emplacement actuel du fichier de script PowerShell?

470
Aaron Jensen

PowerShell 3 +

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

PowerShell 2

Avant PowerShell 3, il n'existait pas de meilleur moyen que d'interroger la propriété MyInvocation.MyCommand.Definition pour les scripts généraux. J'avais la ligne suivante en haut de pratiquement tous les scripts PowerShells que j'avais:

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

Si vous créez un module V2, vous pouvez utiliser une variable automatique appelée $PSScriptRoot.

De PS> Aide automatic_variable

 $ PSScriptRoot 
 Contient le répertoire à partir duquel le module de script est en cours d'exécution. 
 Cette variable permet aux scripts d'utiliser le chemin du module pour accéder à d'autres ressources 
. 
59
Andy Schneider

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

La fonction est alors:

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

Peut-être que quelque chose me manque ici ... mais si vous voulez le répertoire de travail actuel, vous pouvez simplement utiliser ceci: (Get-Location).Path pour une chaîne, ou Get-Location pour un objet.

À moins que vous ne parliez de quelque chose comme ça, ce que je comprends après avoir relu la question.

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

Pour Powershell 3+

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

J'ai placé cette fonction dans mon profil. Fonctionne également dans ISE avec F8/Run Selection.

14
nickkzl

Très similaire aux réponses déjà postées, mais la tuyauterie semble plus proche du PS.

$PSCommandPath | Split-Path -Parent
11
CPAR

J'utilise le variable automatique $ ExecutionContext, cela fonctionne à partir de PowerShell 2 et supérieur.

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

$ ExecutionContext Contient un objet EngineIntrinsics qui représente le contexte d'exécution de l'hôte Windows PowerShell. Vous pouvez utiliser cette variable pour rechercher les objets d'exécution disponibles pour les applets de commande.

10
Viggos

J'avais besoin de connaître le nom du script et d'où il s'exécutait.

La préfixe "$ global:" de la structure MyInvocation renvoie le chemin complet et le nom du script lorsqu'il est appelé à partir du script principal et de la ligne principale d'un fichier de bibliothèque importé .PSM1. Cela fonctionne aussi à partir d'une fonction dans une bibliothèque importée.

Après avoir beaucoup bricolé, j'ai choisi d'utiliser $ global: MyInvocation.InvocationName. Cela fonctionne de manière fiable avec le lancement de CMD, Run With Powershell et ISE. Les lancements locaux et UNC renvoient le chemin correct.

7
Bruce Gavin

Il m'a fallu un certain temps pour développer quelque chose qui prenait la réponse acceptée et la transformait en une fonction robuste.

Pas sûr des autres mais je travaille dans un environnement avec des machines à la fois sur les versions 2 et 3 de PowerShell, donc je devais gérer les deux. La fonction suivante offre une solution de secours élégante:

Function Get-PSScriptRoot
{
    $ScriptRoot = ""

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

    Write-Output $ScriptRoot
}

Cela signifie également que la fonction fait référence à la portée du script plutôt qu'à celle du parent, comme le décrit Michael Sorens dans son blog

7
Bruno

J'utilise toujours ce petit extrait qui fonctionne de la même manière pour Powershell et ISE:

# 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

Vous pouvez également envisager split-path -parent $psISE.CurrentFile.Fullpath si l'une des autres méthodes échoue. En particulier, si vous exécutez un fichier pour charger un ensemble de fonctions, puis que vous exécutez ces fonctions dans le shell ISE (ou si vous exécutez la sélection), il semble que la fonction Get-Script-Directory ne fonctionne pas.

2
user2023266

Constaté que les anciennes solutions publiées ici ne fonctionnaient pas pour moi avec PowerShell V5. Je suis venu avec ceci:

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