312 votes

Dans PowerShell, comment définir une fonction dans un fichier et l'appeler depuis la ligne de commande PowerShell ?

J'ai un fichier .ps1 dans lequel je veux définir des fonctions personnalisées.

Imaginons que le fichier s'appelle MyFunctions.ps1, et que son contenu soit le suivant :

Write-Host "Installing functions"
function A1
{
    Write-Host "A1 is running!"
}
Write-Host "Done"

Pour exécuter ce script et théoriquement enregistrer la fonction A1, je navigue vers le dossier dans lequel réside le fichier .ps1 et j'exécute le fichier :

.\MyFunctions.ps1

Ces sorties :

Installing functions
Done

Pourtant, lorsque j'essaie d'appeler A1, j'obtiens simplement une erreur indiquant qu'il n'existe pas de commande/fonction de ce nom :

The term 'A1' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling
 of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:3
+ A1 <<<<
    + CategoryInfo          : ObjectNotFound: (A1:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Je dois mal comprendre certains concepts de PowerShell. Ne puis-je pas définir des fonctions dans les fichiers script ?

Nota que j'ai déjà défini ma politique d'exécution sur 'RemoteSigned'. Et je sais qu'il faut exécuter les fichiers .ps1 en plaçant un point devant le nom du fichier : . \myFile.ps1

0 votes

Bon lien sur le chargement des fonctions au démarrage du PS : sandfeld.net/powershell-load-your-functions-at-startup

318voto

rsc Points 1339

Essayez ceci sur la ligne de commande PowerShell :

. .\MyFunctions.ps1
A1

L'opérateur point est utilisé pour l'inclusion de script, alias "dot-sourcing" (ou "notation de la source par points" )

0 votes

Je n'avais pas remarqué le petit point supplémentaire que je devais taper. Merci ! Que signifie le premier "." ? Est-ce qu'il signifie "installer" ?

13 votes

Eh bien, cela signifie "exécuter ceci dans le contexte actuel au lieu d'un contexte enfant".

21 votes

Cela signifie source le contenu de ce fichier. Comme dans bash . ss64.com/bash/period.html

288voto

JoeG Points 1034

Ce dont vous parlez s'appelle _sourcing par points . Et c'est le mal. Mais ne vous inquiétez pas, il existe un moyen plus simple et plus efficace de faire ce que vous voulez. modules_ (cela semble bien plus effrayant que cela ne l'est). Le principal avantage de l'utilisation de modules est que vous pouvez les décharger du shell si nécessaire, et que cela empêche les variables des fonctions de s'introduire dans le shell (une fois que vous avez créé le source d'un fichier de fonction, essayez d'appeler une des variables d'une fonction dans le shell, et vous verrez ce que je veux dire).

Tout d'abord, renommez le fichier .ps1 qui contient toutes vos fonctions en MyFunctions.psm1 (vous venez de créer un module !). Maintenant, pour qu'un module se charge correctement, vous devez faire certaines choses spécifiques avec le fichier. Tout d'abord, pour que Import-Module puisse voir le module (vous utilisez cette cmdlet pour charger le module dans le shell), il doit se trouver à un emplacement spécifique. Le chemin par défaut du dossier des modules est $home \Documents\WindowsPowerShell\Modules.

Dans ce dossier, créez un dossier nommé MyFunctions, et placez-y le fichier MyFunctions.psm1 (le fichier du module doit se trouver dans un dossier portant exactement le même nom que le fichier PSM1).

Une fois que c'est fait, ouvrez PowerShell, et exécutez cette commande :

Get-Module -listavailable

Si vous en voyez un appelé MyFunctions, c'est que vous avez bien fait, et votre module est prêt à être chargé (il s'agit juste de s'assurer que tout est bien configuré, vous ne devez le faire qu'une fois).

Pour utiliser le module, tapez ce qui suit dans le shell (ou mettez cette ligne dans votre $profile, ou mettez cette ligne comme première ligne dans un script) :

Import-Module MyFunctions

Vous pouvez maintenant exécuter vos fonctions. Ce qui est bien, c'est qu'une fois que vous avez 10 à 15 fonctions, vous allez oublier le nom de certaines d'entre elles. Si vous les avez placées dans un module, vous pouvez exécuter la commande suivante pour obtenir la liste de toutes les fonctions de votre module :

Get-Command -module MyFunctions

C'est plutôt sympa, et le petit effort qu'il faut faire pour installer la face avant en vaut BEAUCOUP la peine.

7 votes

Et si vos fonctions ne sont pertinentes que pour une application PowerShell donnée ? Je veux dire, si vous installez un paquet de PS1 pour faire un travail quelque part, vous ne voudrez peut-être pas avoir toutes les fonctions dans votre profil, non ?

4 votes

Dans ce cas, je créerais un module pour cette application spécifique, et je le chargerais soit avant d'exécuter les scripts (si vous travaillez de manière interactive), soit dans le script. Mais de manière générale, si vous avez du code qui n'est spécifique qu'à une tâche donnée, vous voudriez que ces fonctions soient dans le script. Personnellement, je n'écris que des fonctions qui font génériquement une chose. Si un morceau de code est hyper spécialisé, cela n'a pas vraiment de sens de l'envelopper dans une fonction ou un module (sauf s'il y a plusieurs scripts qui utilisent ce même code, alors cela pourrait avoir du sens).

0 votes

PS 3 et suivants, placez le module à l'emplacement correct dans le chemin d'accès et il chargera le module lorsque vous entrerez une commande à partir de celui-ci. Par exemple, essayez de taper get-aduser<tab> sur une commande avec le module AD installé mais non chargé. Il chargera alors le module et l'autocomplétion dans `Get-ADUser'. L'emplacement correct dans le chemin dépend. N'importe où dans $PSModulePath fonctionnera.

22voto

yzorg Points 1139

. "$PSScriptRoot\MyFunctions.ps1" MyA1Func

Disponible à partir de la v3, avant cela voir Comment puis-je obtenir l'emplacement du système de fichiers d'un script PowerShell ? . C'est TRÈS courant.

P.S. Je n'adhère pas à la règle du "tout est un module". Mes scripts sont utilisés par d'autres développeurs hors GIT, donc je n'aime pas mettre des trucs à un endroit spécifique ou modifier les variables d'environnement du système avant que mon script ne s'exécute. C'est juste un script (ou deux, ou trois).

0 votes

Pour info, vous n'avez pas besoin de faire l'une ou l'autre de ces choses pour exécuter script dans un module.

0 votes

@NickCox J'aimerais voir des exemples de cela. En avez-vous ? +10 si l'exemple provient d'un projet OSS. Plus précisément, un exemple de module PS chargé via un chemin relatif (pas PSModulePath ou sans personnaliser PSModulePath), et un exemple non trivial (c'est-à-dire où le module présente des avantages par rapport au scoping normal script).

0 votes

J'importe fréquemment les FluentMigrator.PowerShell à partir d'un chemin relatif. Cela nous permet de le vérifier dans le contrôle de la source et de nous assurer que tout le monde utilise la même version. Cela fonctionne bien.

7voto

Jonny Points 2036

Vous pouvez certainement définir des fonctions dans des fichiers script (j'ai ensuite tendance à les charger via mon profil Powershell au chargement).

Tout d'abord, vous devez vérifier que la fonction est chargée en cours d'exécution :

ls function:\ | where { $_.Name -eq "A1"  }

Et vérifiez qu'il apparaît dans la liste (il devrait y avoir une liste de 1 !), puis faites-nous savoir quel résultat vous obtenez !

1 votes

Dans PowerShell, la fonction est traitée comme un répertoire, ce qui revient à dire c:\ ou d : \. De la même manière, vous pouvez utiliser la fonction ls sans la barre oblique inversée : | où { $_.Name -eq "A1" }

7voto

David Morrow Points 41

Vous pouvez ajouter une fonction à :

c:\Users\David\Documents\WindowsPowerShell\profile.ps1

Et la fonction sera disponible.

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