Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Quiero poder decir desde qué ruta se ejecutó el script de ejecución.
Esto a menudo no será $ pwd.

Necesito llamar a otros scripts que están en una estructura de carpetas en relación con mi script y, si bien puedo codificar las rutas, es desagradable y un poco molesto cuando intento promocionar desde " dev " para " prueba " a " producción " ;.

¿Fue útil?

Solución

El script ubicuo originalmente publicado por Jeffrey Snover del equipo de PowerShell (dado en la respuesta de Skyler ) y las variaciones publicadas por Keith Cedirc y EBGreen, todas sufren un serio inconveniente: si el código informa lo que espera, depende de dónde lo llame.

Mi código a continuación soluciona este problema simplemente al hacer referencia al alcance script en lugar del alcance principal :

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

Para ilustrar el problema, creé un vehículo de prueba que evalúa la expresión de destino de cuatro maneras diferentes. (Los términos entre corchetes son las claves de la siguiente tabla de resultados).

  1. código en línea [en línea]
  2. función en línea, es decir, función en el programa principal [función en línea]
  3. Función de origen de puntos, es decir, la misma función movida a un archivo .ps1 separado [fuente de puntos]
  4. Función de módulo, es decir, la misma función se movió a un archivo .psm1 separado [módulo]

Las dos últimas columnas muestran el resultado del uso del alcance del script (es decir, $ script :) o con el alcance principal (con -scope 1). Un resultado de " script " significa que la invocación informó correctamente la ubicación de la secuencia de comandos. El módulo " " resultado significa que la invocación informó la ubicación del módulo que contiene la función en lugar del script que llamó a la función; esto indica un inconveniente de ambas funciones que no puede colocar la función en un módulo.

Aparte del aspecto del módulo, la observación destacada de la tabla es que el uso del enfoque de alcance principal falla la mayor parte del tiempo (de hecho, con el doble de frecuencia que con éxito).

tabla de combinaciones de entrada

Finalmente, aquí está el vehículo de prueba:

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

Contenido de ScriptDirFinder.ps1:

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

Contenido de ScriptDirFinder.psm1:

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

No estoy familiarizado con lo que se introdujo en PowerShell 2, pero podría ser que el alcance del script no existiera en PowerShell 1, en el momento en que Jeffrey Snover publicó su ejemplo.

Me sorprendió cuando, aunque encontré que su ejemplo de código proliferaba en la web, ¡falló inmediatamente cuando lo probé! Pero eso fue porque lo usé de manera diferente al ejemplo de Snover (no lo llamé en la parte superior del script, sino desde dentro de otra función (mi ejemplo "anidado").

2011.09.12 Actualización

Puedes leer sobre esto con otros consejos y trucos sobre módulos en mi artículo recién publicado en Simple-Talk.com: Más adelante Por el agujero del conejo: módulos PowerShell y encapsulación .

Otros consejos

Marcó su pregunta para la versión 1.0 de Powershell; sin embargo, si tiene acceso a la versión 3.0 de Powershell, sabe que tiene $ PSCommandPath y $ PSScriptRoot , lo que facilita la obtención de la ruta del script un poco mas facil Consulte la " OTRAS FUNCIONES DE ESCRITURA " sección en esta página para más información.

Hemos estado usando código como este en la mayoría de nuestros scripts durante varios años sin problemas:

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

Me encontré con el mismo problema recientemente. El siguiente artículo me ayudó a resolver el problema: http: // blogs.msdn.com/powershell/archive/2007/06/19/get-scriptdirectory.aspx

Si no está interesado en cómo funciona, aquí tiene todo el código que necesita por artículo:

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

Y luego obtienes la ruta simplemente haciendo:

$path = Get-ScriptDirectory

Creo que puedes encontrar la ruta de tu script en ejecución

$MyInvocation.MyCommand.Path

Espero que ayude!

Cédric

Esta es una de esas rarezas (al menos para mi mente) en PS. Estoy seguro de que hay una buena razón para ello, pero aún me parece extraño. Entonces:

Si está en un script pero no en una función, entonces $ myInvocation.InvocationName le dará la ruta completa, incluido el nombre del script. Si estás en un script y dentro de una función, $ myInvocation.ScriptName te dará lo mismo.

Gracias señor! Esto realmente me ayudó con mi módulo personalizado. En caso de que alguien esté interesado en hacer lo suyo, aquí está cómo está estructurado el mío.

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

Luego haces referencia a MyScriptFile.ps1 en MyModule.psd1. La referencia a .ps1 en la matriz NestedModules colocará las funciones en el estado de sesión del módulo en lugar del estado de sesión global. ( Cómo escribir un manifiesto del módulo )

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

Contenido de MyScriptFile.ps1

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

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

El try / catch oculta el error de Export-ModuleMember cuando ejecuta MyScriptFile.ps1

Copie el directorio MyModule en una de las rutas encontradas aquí $env:PSModulePath

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

CommandType     Name                                               ModuleName                                                                                                                                                
-----------     ----                                               ----------                                                                                                                                                
Function        Get-ScriptDirectory                                MyModule  
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top