web-dev-qa-db-fra.com

PowerShell: Exécuter une commande à partir du répertoire du script

J'ai un script PowerShell qui effectue certaines tâches en utilisant le répertoire actuel du script. Ainsi, lorsque vous vous trouvez dans ce répertoire, exécuter .\script.ps1 fonctionne correctement.

Maintenant, je veux appeler ce script depuis un autre répertoire sans changer le répertoire de référence du script. Donc, je veux appeler ..\..\dir\script.ps1 et je veux toujours que ce script se comporte comme il a été appelé depuis son répertoire.

Comment puis-je le faire ou comment modifier un script pour qu'il puisse être exécuté à partir de n'importe quel répertoire?

130
poke

Voulez-vous dire que vous voulez le propre chemin du script afin que vous puissiez référencer un fichier à côté du script? Essaye ça:

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

Vous pouvez obtenir beaucoup d’informations sur $ MyInvocation et ses propriétés.

Si vous souhaitez référencer un fichier dans le répertoire de travail en cours, vous pouvez utiliser Resolve-Path ou Get-ChildItem:

$filepath = Resolve-Path "somefile.txt"

EDIT (basé sur le commentaire de l'OP):

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

# do stuff, call ant, etc

# now back to previous directory
Pop-Location

Il y a probablement d'autres moyens de réaliser quelque chose de similaire en utilisant Invoke-Command.

178
JohnL

Si vous appelez des applications natives, vous devez vous soucier de [Environment]::CurrentDirectory et non du répertoire actuel de PowerShell $PWD. Pour diverses raisons, PowerShell ne définit pas le répertoire de travail actuel du processus lors de la définition de l'emplacement ou de l'emplacement de transfert. Vous devez donc vous assurer de le faire si vous exécutez des applications (ou des cmdlets) qui supposent qu'il soit défini.

Dans un script, vous pouvez faire ceci:

$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

Il n'y a pas d'alternative infaillible à cela. Beaucoup d'entre nous ont mis une ligne dans notre fonction Invite pour définir [Environment] :: CurrentDirectory ... mais cela ne vous aide pas lorsque vous modifiez l'emplacement à l'intérieur un script.

Deux remarques sur la raison pour laquelle cela n'est pas défini automatiquement par PowerShell:

  1. PowerShell peut être multi-threadé. Vous pouvez avoir plusieurs Runspaces (voir RunspacePool et le module PSThreadJob) s'exécutant simultanément dans un même processus. Chaque espace d'exécution a son propre répertoire de travail $PWD, mais il n'y a qu'un seul processus et un seul environnement.
  2. Même lorsque vous utilisez un seul thread, $PWD n'est pas toujours un CurrentDirectory légal (vous pouvez par exemple insérer un CD dans le fournisseur de registre).

Si vous souhaitez le placer dans votre invite (qui ne s'exécutera que dans l'espace d'exécution principal, à thread unique), vous devez utiliser:

[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem
32
Jaykul

Il y a des réponses avec un grand nombre de votes, mais quand j'ai lu votre question, je pensais que vous vouliez connaître le répertoire dans lequel se trouve le script, et non celui où il est exécuté. Vous pouvez obtenir les informations avec les variables automatiques 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

Par exemple, j'ai le script $ profile qui trouve le fichier solution Visual Studio et le démarre. Je voulais stocker le chemin complet une fois qu'un fichier de solution est démarré. Mais je voulais enregistrer le fichier où le script original existe. J'ai donc utilisé $ PsScriptRoot.

31
Andy

J'ai souvent utilisé le code suivant pour importer un module situé dans le même répertoire que le script en cours d'exécution. Il obtiendra d’abord le répertoire à partir duquel Powershell est lancé

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

module d'importation "$ currentPath\sqlps.ps1"

12
Daniel Wu

Cela fonctionnerait bien.

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir
3
ArunSK

Eh bien, je cherchais une solution pour cela pendant un moment, sans aucun script en provenance de CLI. Voici comment je le fais xD:

  • Naviguez jusqu'au dossier à partir duquel vous voulez exécuter le script (l'important est que vous ayez terminé les onglets)

    ..\..\dir

  • Maintenant, entourez location de guillemets doubles, et à l'intérieur, ajoutez cd afin de pouvoir appeler une autre instance de powershell.

    "cd ..\..\dir"

  • Ajouter une autre commande pour exécuter le script séparé par ;, avec un séparateur de commande dans Powershell

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

  • Enfin, lancez-le avec une autre instance de powershell

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

Cela ouvrira une nouvelle fenêtre Powershell, allez à ..\..\dir, exécutez script.ps1 et fermez la fenêtre.


Notez que ";" Séparez simplement les commandes, comme si vous les tapiez une par une, si la première échoue, la seconde sera exécutée, puis après, et ensuite après ... Si vous voulez garder la nouvelle fenêtre powershell ouverte, ajoutez -noexit dans la commande passée. Notez que je navigue d’abord dans le dossier souhaité pour pouvoir utiliser les complétions d’onglet (vous ne pouviez pas utiliser de guillemets).

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

Utilisez des guillemets doubles "" pour pouvoir passer des répertoires avec des espaces dans les noms, par exemple,

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

2
IGRACH