62 votes

Comment puis-je trouver le chemin source d'un script en cours d'exécution ?

Je veux être capable de dire à partir de quel chemin mon script a été exécuté.
Souvent, ce ne sera pas $pwd.

J'ai besoin d'appeler d'autres scripts qui se trouvent dans une structure de dossiers relative à mon script et bien que je puisse coder en dur les chemins, c'est à la fois désagréable et un peu pénible quand on essaie de passer de "dev" à "test" puis à "production".

0 votes

Et les chemins fixes ne sont pas fiables si l'utilisateur installe le logiciel ailleurs que là où vous l'attendiez...

3 votes

Ummm.... ma question a été marquée comme étant un doublon d'une question posée presque exactement deux ans auparavant. après le mien ? WTF ?

1 votes

On peut dire que ce n'est pas la bonne façon de faire la duplication - en général, la question la plus ancienne devrait être la question principale (canonique). La question de savoir si cela vaut la peine d'être corrigé est moins claire - demandez peut-être à la MSO. Je note que le doublon est lui-même marqué comme un doublon possible d'une question de type troisième question qui a également été posée après celle-ci.

100voto

Michael Sorens Points 9637

L'omniprésent script posté à l'origine par Jeffrey Snover de l'équipe PowerShell (donnée dans La réponse de Skyler ) et les variations postées par Keith Cedirc, et EBGreen, souffrent toutes d'un sérieux inconvénient-- le fait que le code rapporte ce que vous attendez dépend de l'endroit où vous l'appelez !

Mon code ci-dessous résout ce problème en référençant simplement script au lieu de parent l'étendue :

function Get-ScriptDirectory
{
    Split-Path $script:MyInvocation.MyCommand.Path
}

Pour illustrer le problème, j'ai créé un véhicule de test qui évalue l'expression cible de quatre manières différentes. (Les termes entre parenthèses sont les clés du tableau de résultats suivant).

  1. code en ligne [en ligne]
  2. fonction inline, c'est-à-dire fonction dans le programme principal [fonction inline].
  3. Fonction "dot-sourced", c'est-à-dire que la même fonction est déplacée dans un fichier .ps1 distinct [dot source].
  4. Fonction de module, c'est-à-dire la même fonction déplacée dans un fichier .psm1 distinct [module].

Les deux dernières colonnes montrent le résultat de l'utilisation de la portée script (c'est-à-dire $script :) ou avec la portée parent (avec -scope 1). Un résultat de "script" signifie que l'invocation a correctement signalé l'emplacement du script. Le résultat "module" signifie que l'invocation a signalé l'emplacement du module contenant la fonction plutôt que le script qui a appelé la fonction ; cela indique un inconvénient des deux fonctions, à savoir que vous ne pouvez pas placer la fonction dans un module.

Si l'on met de côté la question du module, l'observation remarquable du tableau est que L'utilisation de l'approche de la portée parentale échoue la plupart du temps. (en fait, deux fois plus souvent qu'elle ne réussit).

table of input combinations

Enfin, voici le véhicule d'essai :

function DoubleNested()
{
    "=== DOUBLE NESTED ==="
    NestCall
}

function NestCall()
{
    "=== NESTED ==="
    "top level:"
    Split-Path $script:MyInvocation.MyCommand.Path
    #$foo = (Get-Variable MyInvocation -Scope 1).Value
    #Split-Path $foo.MyCommand.Path
    "immediate func call"
    Get-ScriptDirectory1
    "dot-source call"
    Get-ScriptDirectory2
    "module call"
    Get-ScriptDirectory3
}

function Get-ScriptDirectory1
{
    Split-Path $script:MyInvocation.MyCommand.Path
    # $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    # Split-Path $Invocation.MyCommand.Path
}

. .\ScriptDirFinder.ps1
Import-Module ScriptDirFinder -force

"top level:"
Split-Path $script:MyInvocation.MyCommand.Path
#$foo = (Get-Variable MyInvocation -Scope 1).Value
#Split-Path $foo.MyCommand.Path

"immediate func call"
Get-ScriptDirectory1
"dot-source call"
Get-ScriptDirectory2
"module call"
Get-ScriptDirectory3

NestCall
DoubleNested

Contenu de ScriptDirFinder.ps1 :

function Get-ScriptDirectory2
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

Contenu de ScriptDirFinder.psm1 :

function Get-ScriptDirectory3
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

Je ne suis pas au courant de ce qui a été introduit dans PowerShell 2, mais il se pourrait très bien que la portée script n'existait pas dans PowerShell 1, au moment où Jeffrey Snover a publié son exemple.

J'ai été surpris quand, bien que j'aie trouvé son exemple de code proliférant partout sur le web, il a échoué immédiatement quand je l'ai essayé ! Mais c'était parce que je l'ai utilisé différemment de l'exemple de Snover (je ne l'ai pas appelé au script-top mais à l'intérieur d'une autre fonction (mon exemple "imbriqué deux fois")).

Mise à jour 2011.09.12

Vous pouvez lire ce sujet, ainsi que d'autres conseils et astuces sur les modules, dans mon article qui vient d'être publié sur Simple-Talk.com : Plus loin dans le terrier du lapin : modules PowerShell et encapsulation .

22voto

Michael Kelley Points 1153

Vous avez marqué votre question pour Powershell version 1.0, cependant, si vous avez accès à Powershell version 3.0 vous savez avoir $PSCommandPath y $PSScriptRoot ce qui rend l'obtention du chemin script un peu plus facile. Veuillez vous référer au "AUTRES FONCTIONNALITES script" de cette page pour plus d'informations.

1 votes

Brillant. Merci d'avoir ajouté cette information actuelle. Il se trouve que je le savais, mais le prochain qui cherche ne le saura probablement pas mais sera sur une version actuelle de PoSh.

11voto

Keith Hill Points 73162

Nous utilisons ce type de code dans la plupart de nos scripts depuis plusieurs années sans aucun problème :

#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir  = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1

2 votes

Notez que cela ne fonctionne pas lorsqu'il est appelé à l'intérieur d'une fonction.

0 votes

Vrai, vous devez préfixer "script :" comme dans la réponse acceptée $script:MyInvocation.MyCommand.Path

6voto

Skyler Points 244

J'ai rencontré le même problème récemment. L'article suivant m'a aidé à résoudre le problème : http://blogs.msdn.com/powershell/archive/2007/06/19/get-scriptdirectory.aspx

Si vous n'êtes pas intéressé par son fonctionnement, voici tout le code dont vous avez besoin selon l'article :

function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

Et puis vous obtenez le chemin en faisant simplement :

$path = Get-ScriptDirectory

5voto

Cédric Rup Points 5363

Je pense que vous pouvez trouver le chemin de votre script en cours d'exécution en utilisant

$MyInvocation.MyCommand.Path

J'espère que cela vous aidera !

Cédric

4 votes

Cela vous donnera le chemin complet incluant le nom du script tant que vous n'êtes pas dans une fonction. Si vous êtes dans une fonction, ce sera $null.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X