165 votes

PowerShell : Exécuter une commande depuis le répertoire de script.

J'ai un script PowerShell qui fait certaines choses en utilisant le répertoire courant du script. Ainsi, à l'intérieur de ce répertoire, l'exécution de .\script.ps1 fonctionne correctement.

Maintenant je veux appeler ce script à partir d'un répertoire différent sans changer le répertoire de référencement du script. Je veux donc appeler ..\..\dir\script.ps1 tout en voulant que ce script se comporte comme s'il était appelé depuis son répertoire.

Comment faire, ou comment modifier un script pour qu'il puisse être exécuté depuis n'importe quel répertoire ?

221voto

JohnL Points 1860

Voulez-vous dire que vous voulez que le script ait son propre chemin d'accès afin de pouvoir référencer un fichier à côté du script ? Essayez ceci :

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

Vous pouvez obtenir beaucoup d'informations à partir de $MyInvocation et de ses propriétés.

Si vous voulez faire référence à un fichier dans le répertoire de travail actuel, 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 $dir

# do stuff, call ant, etc

# now back to previous directory
Pop-Location

Il existe probablement d'autres moyens d'obtenir quelque chose de similaire en utilisant Invoke-Command.

1 votes

Hmm, ok, j'aurais peut-être dû être un peu plus clair sur mon script. En fait c'est un script qui appelle ant avec certains paramètres. Je dois donc appeler ant de ce dossier pour s'assurer qu'il trouve le fichier de configuration correctement. Idéalement, je cherche quelque chose pour changer temporairement le répertoire d'exécution localement dans ce script.

4 votes

Ah alors dans ce cas, vous voudrez Push-Location y Pop-Location

5 votes

Attention, $MyInvocation est sensible au contexte, je fais habituellement $ScriptPath = (Get-Variable MyInvocation -Scope script).Value.MyCommand.Path qui fonctionne à partir de n'importe quelle sorte d'imbrication ou de fonction.

53voto

Andy Points 1118

Il y a des réponses avec un grand nombre de votes, mais quand j'ai lu votre question, j'ai pensé que vous vouliez connaître le répertoire où se trouve le script, et non celui où le script s'exécute. Vous pouvez obtenir l'information 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 un $profile script qui trouve un fichier de solution Visual Studio et le lance. 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 .

2 votes

La réponse que je cherchais. Les autres semblent résoudre plus de problèmes que la réponse directe.

41voto

Jaykul Points 6484

Si vous appelez des applications natives, vous devez vous préoccuper des points suivants [Environment]::CurrentDirectory pas à propos de PowerShell $PWD répertoire actuel. Pour diverses raisons, PowerShell ne définit pas le répertoire de travail actuel du processus lorsque vous utilisez Set-Location ou Push-Location. Vous devez donc vous assurer de le faire si vous exécutez des applications (ou des cmdlets) qui s'attendent à ce qu'il soit défini.

Dans un script, vous pouvez faire cela :

$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 insèrent une ligne dans notre fonction d'invite pour définir [Environment]::CurrentDirectory ... mais cela ne vous aide pas lorsque vous changez l'emplacement de votre ordinateur. sur un script.

Deux remarques sur la raison pour laquelle ce paramètre n'est pas défini automatiquement par PowerShell :

  1. PowerShell peut être multithreadé. Vous pouvez avoir plusieurs espaces d'exécution (voir RunspacePool, et le module PSThreadJob) fonctionnant simultanément dans un seul processus. Chaque espace d'exécution possède son propre $PWD le répertoire de travail actuel, mais il n'y a qu'un seul processus, et un seul environnement.
  2. Même lorsque vous êtes en monofilière, $PWD n'est pas toujours un CurrentDirectory légal (vous pouvez par exemple utiliser le CD dans le fournisseur de registre).

Si vous voulez le mettre dans votre prompt (qui ne s'exécutera que dans l'espace d'exécution principal, en mode monofilaire), vous devez utiliser :

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

4 votes

Il ne change pas le répertoire de travail du processus à cause des fournisseurs de chemins : vous pourriez être en train de CD'ing dans le registre, une base de données SQL ou une ruche IIS etc....

1 votes

Oui. Je sais, c'était le but de cette dernière "note finale". Ils auraient pu (comme je le fais dans ma fonction d'invite) le mettre à jour à l'emplacement actuel du fournisseur de système de fichiers, comme tous les autres shells du monde.

2 votes

Par les dieux du script, je suis tellement déçu. .\_/. - car ça a tué la moitié de ma journée ! Les gens, sérieusement ? Sérieusement

13voto

ArunSK Points 121

Cela fonctionnerait très bien.

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir

2 votes

N'oubliez pas d'appeler Pop-Location à la fin pour ramener le chemin à son état d'origine.

12voto

Daniel Wu Points 783

J'ai souvent utilisé le code suivant pour importer un module qui se trouve dans le même répertoire que le script en cours d'exécution. Il va d'abord récupérer le répertoire à partir duquel powershell est exécuté.

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

import-module "$currentPath \sqlps.ps1 "

0 votes

Vous voulez mettre le -Scope à script

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X