¿Cuál es la mejor manera de determinar la ubicación del script de PowerShell actual?

Cada vez que necesito hacer referencia a un módulo o secuencia de comandos común, me gusta utilizar rutas relativas al archivo de secuencia de comandos actual, de esa manera, mi secuencia de comandos siempre puede encontrar otras secuencias de comandos en la biblioteca.

Entonces, ¿cuál es la mejor forma estándar de determinar el directorio del script actual? Actualmente, estoy haciendo:

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

Sé en los módulos (.psm1) que puede usar $PSScriptRoot para obtener esta información, pero eso no se establece en las secuencias de comandos regulares (es decir, archivos .ps1).

¿Cuál es la forma canónica de obtener la ubicación actual del archivo de script de PowerShell?

PowerShell 3+

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

PowerShell 2

Antes de PowerShell 3, no había una mejor manera que consultar la propiedad MyInvocation.MyCommand.Definition para scripts generales. Tenía la siguiente línea en la parte superior de cada script de powershell que tenía:

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

Si está creando un Módulo V2, puede usar una variable automática llamada $PSScriptRoot .

De PS> Ayuda automatic_variable

 $ PSScriptRoot
        Contiene el directorio desde el cual se está ejecutando el módulo de script.
        Esta variable permite que los scripts usen la ruta del módulo para acceder a otros
        recursos.

Para 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 función es entonces:

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

Quizás me falta algo aquí … pero si quieres el directorio de trabajo actual, puedes usar esto: (Get-Location).Path para una cadena, o Get-Location para un objeto.

A menos que te refieras a algo como esto, lo cual entiendo después de leer la pregunta nuevamente.

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

Utilizo la variable automática $ ExecutionContext, funciona desde PowerShell 2 y posterior.

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

$ ExecutionContext Contiene un objeto EngineIntrinsics que representa el contexto de ejecución del host de Windows PowerShell. Puede usar esta variable para buscar los objetos de ejecución que están disponibles para los cmdlets.

Necesitaba saber el nombre del script y desde dónde se está ejecutando.

El prefijo “$ global:” a la estructura MyInvocation devuelve la ruta completa y el nombre del script cuando se llama tanto desde el script principal como desde la línea principal de un archivo de biblioteca .PSM1 importado. También funciona desde dentro de una función en una biblioteca importada.

Después de mucho alboroto, decidí usar $ global: MyInvocation.InvocationName. Funciona de manera confiable con el lanzamiento de CMD, Run With Powershell y el ISE. Los lanzamientos locales y UNC devuelven la ruta correcta.

Me tomó un tiempo desarrollar algo que tomara la respuesta aceptada y la convirtiera en una función robusta.

No estoy seguro de los demás, pero trabajo en un entorno con máquinas en las versiones 2 y 3 de PowerShell, así que necesitaba manejar ambas. La siguiente función ofrece una elegante alternativa:

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

También significa que la función se refiere al scope de Script en lugar del scope de los padres, tal como lo describe Michael Sorens en su blog.

Muy similar a las respuestas ya publicadas, pero las tuberías parecen más parecidas a las de PS.

 $PSCommandPath | Split-Path -Parent 

Para Powershell 3+

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

He colocado esta función en mi perfil. Funciona en ISE usando F8 / Run Selection también.

También puede considerar split-path -parent $psISE.CurrentFile.Fullpath si split-path -parent $psISE.CurrentFile.Fullpath alguno de los otros métodos. En particular, si ejecuta un archivo para cargar un conjunto de funciones y luego ejecuta esas funciones con -en el shell ISE (o si ejecuta-seleccionado), parece que la función Get-Script-Directory como la anterior no funciona.

 function func1() { $inv = (Get-Variable MyInvocation -Scope 1).Value #$inv.MyCommand | Format-List * $Path1 = Split-Path $inv.scriptname Write-Host $Path1 } function Main() { func1 } Main