Question

    

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

         

Je veux pouvoir indiquer le chemin depuis lequel mon script d'exécution a été exécuté.
Ce ne sera souvent pas $ pwd.

Je dois appeler d'autres scripts situés dans une structure de dossiers relative à mon script. Bien que je puisse coder les chemins en dur, c'est à la fois désagréable et un peu pénible lorsque j'essaie de promouvoir "& dev". pour " tester " de "production".

Était-ce utile?

La solution

Le script omniprésent publié à l'origine par Jeffrey Snover de l'équipe PowerShell (donnée dans la réponse de Skyler ) et les variantes publiées par Keith Cedirc et EBGreen, souffrent toutes de un sérieux inconvénient - que 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 référençant simplement la portée de script au lieu de la portée parent :

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

Pour illustrer ce problème, j'ai créé un véhicule test qui évalue l'expression cible de quatre manières différentes. (Les termes entre crochets sont les clés de la table de résultats suivante.)

  1. code en ligne [en ligne]
  2. fonction inline, c.-à-d. fonction dans le programme principal [fonction inline]
  3. Fonction source, c'est-à-dire que la même fonction a été déplacée vers un fichier .ps1 distinct [source de points]
  4. Fonction du module, c’est-à-dire que la même fonction a été déplacée dans un fichier .psm1 séparé [module]

Les deux dernières colonnes montrent le résultat de l'utilisation de la portée du script (c'est-à-dire $ script :) ou de la portée parent (avec -scope 1). Un résultat de " script " signifie que l'invocation a correctement indiqué l'emplacement du script. Le " module " result 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 que vous ne pouvez pas la mettre dans un module.

Abstraction faite de la question du module, l'observation remarquable du tableau est que l'utilisation de l'approche de l'étendue parent échoue la plupart du temps (en fait, deux fois plus de fois que l'opération réussit).

tableau des combinaisons d'entrées

Enfin, voici le véhicule de test:

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 du script n’existe pas dans PowerShell 1, au moment où Jeffrey Snover a publié son exemple.

J'ai été surpris quand, bien que son exemple de code ait proliféré sur le Web, il a immédiatement échoué lorsque j'ai essayé! Mais c’est parce que je l’ai utilisée différemment de l’exemple de Snover (je ne l’ai pas appelé depuis script-top mais depuis une autre fonction (mon exemple "imbriqué deux fois").)

Mise à jour 2011.09.12

Vous pouvez lire à ce sujet avec d'autres trucs et astuces sur les modules dans mon article qui vient de paraître sur Simple-Talk.com: Suivant Dans le trou du lapin: modules et encapsulation de PowerShell .

Autres conseils

Vous avez marqué votre question pour Powershell version 1.0; cependant, si vous avez accès à Powershell version 3.0, vous savez que $ PSCommandPath et $ PSScriptRoot permettent d'obtenir le chemin du script un peu plus facile. Reportez-vous à la & AUTRES FONCTIONS DE SCRIPT " section sur cette page pour plus d'informations.

Nous utilisons un code comme celui-ci 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

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 cela ne vous intéresse pas, 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

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

$MyInvocation.MyCommand.Path

J'espère que ça aide!

C & # 233; dric

C’est l’une de ces bizarreries (du moins selon moi) dans PS. Je suis sûr qu'il y a une raison parfaitement valable pour cela, mais cela me semble toujours étrange. Donc:

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

Merci beaucoup! Cela m'a vraiment aidé avec mon module personnalisé. Au cas où quelqu'un voudrait créer le sien, voici comment le mien est structuré.

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

Vous faites ensuite référence à MyScriptFile.ps1 dans MyModule.psd1. Référencer le fichier .ps1 dans le tableau NestedModules placera les fonctions dans l'état de session du module plutôt que dans l'état de session global. ( Comment rédiger 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{}

La commande try / catch masque l'erreur d'Export-ModuleMember lors de l'exécution de MyScriptFile.ps1

Copiez le répertoire MyModule dans l'un des chemins indiqués ici $ env: PSModulePath

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

CommandType     Name                                               ModuleName                                                                                                                                                
-----------     ----                                               ----------                                                                                                                                                
Function        Get-ScriptDirectory                                MyModule  
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top