PowerShell: Ejecute el comando desde el directorio del script

144

Tengo un script de PowerShell que hace algunas cosas usando el directorio actual del script. Entonces, dentro de ese directorio, la ejecución .\script.ps1funciona correctamente.

Ahora quiero llamar a ese script desde un directorio diferente sin cambiar el directorio de referencia del script. Entonces quiero llamar ..\..\dir\script.ps1y todavía quiero que ese script se comporte como se llamó desde dentro de su directorio.

¿Cómo hago eso, o cómo modifico un script para que pueda ejecutarse desde cualquier directorio?

dar un toque
fuente

Respuestas:

200

¿Quiere decir que desea la ruta del script para poder hacer referencia a un archivo al lado del script? Prueba esto:

$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Write-host "My directory is $dir"

Puede obtener mucha información de $ MyInvocation y sus propiedades.

Si desea hacer referencia a un archivo en el directorio de trabajo actual, puede usar Resolve-Path o Get-ChildItem:

$filepath = Resolve-Path "somefile.txt"

EDITAR (basado en el comentario de OP):

# temporarily change to the correct folder
Push-Location $folder

# do stuff, call ant, etc

# now back to previous directory
Pop-Location

Probablemente hay otras formas de lograr algo similar usando Invoke-Command también.

JohnL
fuente
1
Hmm, está bien, tal vez debería haber sido un poco más claro sobre mi guión. En realidad es un script que llama antcon algunos parámetros. Entonces tengo que llamar antdesde esa carpeta para asegurarme de que encuentre el archivo de configuración correctamente. Idealmente, estoy buscando algo para cambiar temporalmente el directorio de ejecución localmente dentro de ese script.
meter
3
Ah, entonces en ese caso querrás Push-LocationyPop-Location
JohnL
55
cuidado con eso, $ MyInvocation es sensible al contexto, generalmente hago $ ScriptPath = (Get-Variable MyInvocation -Scope Script) .Value.MyCommand.Path que funciona desde cualquier tipo de anidamiento o función
Ion Todirel
39

Si llama a aplicaciones nativas, no debe preocuparse por [Environment]::CurrentDirectoryel $PWDdirectorio actual de PowerShell . Por varias razones, PowerShell no establece el directorio de trabajo actual del proceso cuando establece la ubicación o la ubicación de inserción, por lo que debe asegurarse de hacerlo si está ejecutando aplicaciones (o cmdlets) que esperan que se establezca.

En un script, puedes hacer esto:

$CWD = [Environment]::CurrentDirectory

Push-Location $MyInvocation.MyCommand.Path
[Environment]::CurrentDirectory = $PWD
##  Your script code calling a native executable
Pop-Location

# Consider whether you really want to set it back:
# What if another runspace has set it in-between calls?
[Environment]::CurrentDirectory = $CWD

No hay alternativa infalible a esto. Muchos de nosotros ponemos una línea en nuestra función de solicitud para establecer [Environment] :: CurrentDirectory ... pero eso no te ayuda cuando cambias la ubicación dentro de un script.

Dos notas sobre el motivo por el cual PowerShell no establece esto automáticamente:

  1. PowerShell puede ser multiproceso. Puede tener múltiples Runspaces (consulte RunspacePool y el módulo PSThreadJob) ejecutándose simultáneamente en un solo proceso. Cada espacio de ejecución tiene su propio $PWDdirectorio de trabajo actual, pero solo hay un proceso y solo un entorno.
  2. Incluso cuando tiene un solo subproceso, $PWDno siempre es un CurrentDirectory legal (por ejemplo, puede incluir un CD en el proveedor de registro).

Si desea ponerlo en su solicitud (que solo se ejecutaría en el espacio de ejecución principal, de un solo subproceso), debe usar:

[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem
Jaykul
fuente
44
No cambia el directorio proceso de trabajo debido a los proveedores de ruta: es posible que de cambiar al registro, una base de datos SQL o un IIS colmena etc ...
piers7
1
Si. Lo sé, ese fue el punto de esa última "Nota final". Podrían haberlo actualizado (como lo hago en mi función de solicitud) a la ubicación actual del proveedor de FileSystem, como cualquier otro shell del mundo.
Jaykul
2
Dioses de la escritura, estoy tan decepcionado .\_/., ¡porque esto mató la mitad de mi día! ¿Gente en serio? ¿En serio? ..
ulidtko
2
Ahora es casi innecesario, las versiones más modernas de PowerShell establecen el directorio de trabajo cuando lanzan aplicaciones binarias.
Jaykul
1
Este método falla al restaurar el original [Environment]::CurrentDirectorycuando eso difiere de $PWD. Lo correcto sería almacenarlo en una variable $origEnvDir = [Environment]::CurrentDirectoryy luego restaurarlo [Environment]::CurrentDirectory = $origEnvDir.
Strom
37

Hay respuestas con gran cantidad de votos, pero cuando leí tu pregunta, pensé que querías saber el directorio donde está el script, no aquel donde se está ejecutando el script. Puede obtener la información con las variables automáticas de powershell

$PSScriptRoot - the directory where the script exists, not the target directory the script is running in
$PSCommandPath - the full path of the script

Por ejemplo, tengo un script de $ profile que encuentra el archivo de solución de Visual Studio y lo inicia. Quería almacenar la ruta completa, una vez que se inicia un archivo de solución. Pero quería guardar el archivo donde existe el script original. Entonces usé $ PsScriptRoot.

Andy
fuente
12

A menudo utilicé el siguiente código para importar un módulo que se encuentra en el mismo directorio que el script en ejecución. Primero obtendrá el directorio desde el que se ejecuta powershell

$ currentPath = Split-Path ((Get-Variable MyInvocation -Scope 0) .Value) .MyCommand.Path

módulo de importación "$ currentPath \ sqlps.ps1"

Daniel Wu
fuente
desea configurar -Scope a Script
Ion Todirel
9

Esto funcionaría bien.

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir
ArunSK
fuente
No olvide llamar Pop-Locational final para devolver la ruta a su estado original.
Lam Le
2

Bueno, estuve buscando una solución para esto por un tiempo, sin ningún script solo de CLI. Así es como lo hago xD:

  • Navegue a la carpeta desde la que desea ejecutar la secuencia de comandos (lo importante es que tenga las pestañas completadas)

    ..\..\dir

  • Ahora rodee la ubicación con comillas dobles, y agregue dentro de ellas cd, para que podamos invocar otra instancia de powershell.

    "cd ..\..\dir"

  • Agregue otro comando para ejecutar el script separado por ;, con un separador de comandos en powershell

    "cd ..\..\dir\; script.ps1"

  • Finalmente ejecutarlo con otra instancia de powershell

    start powershell "cd..\..\dir\; script.ps1"

Esto abrirá una nueva ventana de PowerShell, vaya a ..\..\dir, ejecute script.ps1y cierre la ventana.


Tenga en cuenta que ";" simplemente separa los comandos, como los escribió uno por uno, si el primero falla, el segundo se ejecutará y luego el siguiente, y el siguiente después ... Si desea mantener abierta la nueva ventana de PowerShell, agregue -noexit en el comando pasado. Tenga en cuenta que primero navego a la carpeta deseada para poder usar las finalizaciones de tabulación (no podría entre comillas dobles).

start powershell "-noexit cd..\..\dir\; script.ps1"

Utilice comillas dobles ""para poder pasar directorios con espacios en los nombres, por ejemplo,

start powershell "-noexit cd '..\..\my dir'; script.ps1"

IGRACH
fuente
0

Hice una frase con la solución de @ JohnL:

$MyInvocation.MyCommand.Path | Split-Path | Push-Location
sashoalm
fuente