Comment puis-je trouver le chemin source d'un script d'exécution? [dupliquer]

cette question a déjà une réponse ici:

je veux pouvoir dire sur quel chemin mon script d'exécution a été exécuté.

Souvent, ce ne sera pas $ pwd.

j'ai besoin d'appeler d'Autres scripts qui sont dans une structure de dossier par rapport à mon script et bien que je puisse coder dur les chemins, c'est à la fois désagréable et un peu pénible quand on essaye de promouvoir de" dev "à" test "à"production".

57
demandé sur Kiquenet 2009-04-29 15:42:06

7 réponses

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

mon code ci-dessous résout ce problème en faisant simplement référence à script portée au lieu de parent domaine d'application:

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

pour illustrer le problème, j'ai créé un véhicule d'essai qui évalue l'expression cible de quatre façons différentes. (Les Termes entre crochets sont les clés du tableau de résultats suivant.)

  1. code en ligne [inline]
  2. fonction en ligne, c. à d. fonction dans le programme principal [Fonction en ligne]
  3. Point d'origine de la fonction, c'est à dire le même fonction déplacée à une autre .ps1 file [dot source]
  4. fonction du Module, c'est-à-dire la même fonction déplacée dans un Module séparé .psm1 fichier [module]

les deux dernières colonnes montrent le résultat de l'utilisation de script scope (i.e. $script:) ou avec parent scope (with-scope 1). Un résultat de "script" signifie que l'invocation correctement signalé l'emplacement du script. Le "module" signifie l'invocation signalé l'emplacement du module contenant la fonction plutôt que le script qui a appelé la fonction; Ceci indique un inconvénient des deux fonctions que vous ne pouvez pas mettre la fonction dans un module.

mettre la question du module de côté l'observation remarquable du tableau est que en utilisant l'approche de portée de parent échoue la plupart du temps (en fait, deux fois plus souvent qu'elle réussit).

table of input combinations

enfin, voici le test véhicule:

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

content of ScriptDirFinder.ps1:

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

content of 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 familier avec ce qui a été introduit dans PowerShell 2, mais il se pourrait très bien que le script scope n'existait pas dans PowerShell 1, au moment où Jeffrey Snover a publié son exemple.

j'ai été surpris quand, bien que j'ai trouvé son exemple de code proliféré loin et large sur le web, il a échoué immédiatement quand je l'ai essayé! Mais c'est parce que je l'ai utilisé différemment de L'exemple de Snover (Je l'ai appelé non pas à script-top mais de l'intérieur d'une autre fonction (mon exemple "imbriqué deux fois").)

2011.09.12 mise à jour

vous pouvez lire à ce sujet avec d'autres trucs et astuces sur les modules dans mon article sur Simple-Talk.com: plus loin dans le trou de lapin: Modules PowerShell et Encapsulation .

92
répondu Michael Sorens 2017-05-23 12:02:29

vous avez étiqueté votre question pour la version 1.0 de Powershell, cependant, si vous avez accès à la version 3.0 de Powershell vous savez que vous avez $PSCommandPath et $PSScriptRoot ce qui rend l'obtention du chemin de script un peu plus facile. Veuillez vous référer à la section " autres caractéristiques du SCRIPT " sur cette page pour plus d'informations.

18
répondu Michael Kelley 2016-01-28 01:17:46

nous utilisons ce 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
11
répondu Keith Hill 2009-05-01 18:21:01

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 la façon dont il fonctionne, 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
6
répondu Skyler 2009-04-29 16:58:57

je pense que vous pouvez trouver le chemin de votre script en utilisant

$MyInvocation.MyCommand.Path

Espère que cela aide !

Cédric

5
répondu Cédric Rup 2009-04-29 13:41:41

C'est une de ces bizarreries (à mon avis du moins) dans PS. Je suis sûr qu'il y a une bonne raison à cela, mais cela me semble quand même étrange. So:

si vous êtes dans un script mais pas dans une fonction alors $myInvocation.InvocationName vous donnera le chemin complet incluant le nom du script. Si vous êtes dans un script et dans une fonction alors $myInvocation.ScriptName vous donnera la même chose.

1
répondu EBGreen 2009-04-29 13:34:21

Merci msorens! Cela m'a vraiment aidé avec mon module personnalisé. Dans le cas où quelqu'un est intéressé à faire leur propre, voici comment le mien est structuré.

MyModule (folder)
 - MyModule.psd1 (help New-ModuleManifest)
 - MyScriptFile.ps1 (ps1 files are easy to test)

vous faites alors référence à MyScriptFile.ps1 in MyModule.psd1. Référencement du .ps1 dans le tableau NestedModules placera les fonctions dans l'état de session du module plutôt que dans l'état de session globale. ( Comment écrire un manifeste de Module )

NestedModules = @('.\MyScriptFile.ps1','.\MyOtherScriptFile.ps1')

Contenu de MyScriptFile.ps1

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

try {
    Export-ModuleMember -Function "*-*"
}
catch{}

le try/catch cache l'erreur de Export-ModuleMember lors de L'exécution de MyScriptFile.ps1

copier le MyModule répertoire à l'un des chemins trouvés ici $env: PSModulePath

PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule

CommandType     Name                                               ModuleName                                                                                                                                                
-----------     ----                                               ----------                                                                                                                                                
Function        Get-ScriptDirectory                                MyModule  
0
répondu Coding101 2013-01-30 21:27:37