Question [script] extraire une fonction d'un script
- Jacques Barathon
- Auteur du sujet
- Hors Ligne
- Administrateur
-
Réduire
Plus d'informations
- Messages : 576
- Remerciements reçus 0
il y a 17 ans 1 mois #4153
par Jacques Barathon
[script] extraire une fonction d'un script a été créé par Jacques Barathon
Hello,
Voici un script que j'appellerai tout simplement get-function, qui permet de récupérer le corps d'une fonction définie dans un script et de l'exécuter en dehors du contexte du script.
J'ai écrit ce script assez rapidement aujourd'hui en réponse à un collègue qui avait un besoin un peu tarabiscoté. Ce script répond à son besoin, mais plus généralement il peut s'avérer utile quand on voudrait pouvoir charger une fonction sans avoir à \"dot sourcer\" tout le script dans lequel elle est définie.
Attention: ce script s'appuie sur une fonctionnalité apparue avec la v2 CTP communément appelée \"Tokenizer API\". Cette API permet d'énumérer les différents éléments syntaxiques d'un script.
[code:1]
param ($script,$function)
$keywords = \"Function\",\"Filter\"
$text = get-content $script
$errs = $null
$tokens = [management.automation.psparser]::tokenize($text,[ref]$errs)
if ($errs) {throw $errs}
$tokens | where {
$_.type -eq \"Keyword\" `
-and $keywords -contains $_.content `
-and $tokens[$tokens.indexof($_)+1].content -eq $function
} `
| foreach {
$startline = $_.startline
$groupstart = $groupend = 0
$index = $tokens.indexof($_)+1
do {
switch ($tokens[$index].type) {
\"GroupStart\" {$groupstart++}
\"GroupEnd\" {$groupend++}
}
$index++
} until ($groupstart -eq $groupend -and $groupstart -gt 0)
$endline = $tokens[$index-1].endline
($text[($startline-1)..($endline-1)]) -join \"`n\"
}
[/code:1]
Tel quel ce script ne fournit pratiquement aucune gestion des erreurs. Je publierai sans doute une version un peu plus étoffée sur mon blog dans les prochains jours mais je voulais déjà partager ici la première mouture.
Voici un exemple d'utilisation :
[code:1]
PS> # commençons par visualiser le contenu d'un script qui contient plusieurs fonctions :
PS> cat f2.ps1
function bar
{
write-output \"bar executed\"
[string]::join(\":\",(\"function\",\"bar\"«»))
}
filter jazz
{
\"jazzing $_\"
$sum = $sum + $_
}
function foo
{
write-output \"foo executed\"
function innerfoo1 {\"innerfoo1 executed\"}
function innerfoo2 {\"innerfoo2 executed\"}
}
function hello
{
\"hello world\"
}
PS> # chargons la fonction bar (iex est un alias pour invoke-expression) :
PS> $bar = .\get-function f2.ps1 bar
PS> iex $bar
PS> # la fonction est maintenant chargée et disponible, exécutons-la :
PS> bar
bar executed
function:bar
PS> # faisons de même avec la fonction foo :
PS> $foo = .\get-function f2.ps1 foo
PS> iex $foo
PS> foo
foo executed
PS> # essayons avec la fonction innerfoo2, déclarée dans la fonction foo :
PS> innerfoo2
The term 'innerfoo2' 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:10
+ innerfoo2 <<<<
+ CategoryInfo : ObjectNotFound: (innerfoo2:«»String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS> # ... ça ne marche pas, car les deux fonctions
PS> # ... innerfoo1 et innerfoo2 sont privées.
PS> # mais essayons de charger directement innerfoo1 :
PS> $if1 = .\get-function f2.ps1 innerfoo1
PS> iex $if1
PS> # et maintenant exécutons-la :
PS> innerfoo1
innerfoo1 executed
PS> # ... ça marche !
[/code:1]
Et voilà. En espérant que ça vous sera utile.
Janel
Voici un script que j'appellerai tout simplement get-function, qui permet de récupérer le corps d'une fonction définie dans un script et de l'exécuter en dehors du contexte du script.
J'ai écrit ce script assez rapidement aujourd'hui en réponse à un collègue qui avait un besoin un peu tarabiscoté. Ce script répond à son besoin, mais plus généralement il peut s'avérer utile quand on voudrait pouvoir charger une fonction sans avoir à \"dot sourcer\" tout le script dans lequel elle est définie.
Attention: ce script s'appuie sur une fonctionnalité apparue avec la v2 CTP communément appelée \"Tokenizer API\". Cette API permet d'énumérer les différents éléments syntaxiques d'un script.
[code:1]
param ($script,$function)
$keywords = \"Function\",\"Filter\"
$text = get-content $script
$errs = $null
$tokens = [management.automation.psparser]::tokenize($text,[ref]$errs)
if ($errs) {throw $errs}
$tokens | where {
$_.type -eq \"Keyword\" `
-and $keywords -contains $_.content `
-and $tokens[$tokens.indexof($_)+1].content -eq $function
} `
| foreach {
$startline = $_.startline
$groupstart = $groupend = 0
$index = $tokens.indexof($_)+1
do {
switch ($tokens[$index].type) {
\"GroupStart\" {$groupstart++}
\"GroupEnd\" {$groupend++}
}
$index++
} until ($groupstart -eq $groupend -and $groupstart -gt 0)
$endline = $tokens[$index-1].endline
($text[($startline-1)..($endline-1)]) -join \"`n\"
}
[/code:1]
Tel quel ce script ne fournit pratiquement aucune gestion des erreurs. Je publierai sans doute une version un peu plus étoffée sur mon blog dans les prochains jours mais je voulais déjà partager ici la première mouture.
Voici un exemple d'utilisation :
[code:1]
PS> # commençons par visualiser le contenu d'un script qui contient plusieurs fonctions :
PS> cat f2.ps1
function bar
{
write-output \"bar executed\"
[string]::join(\":\",(\"function\",\"bar\"«»))
}
filter jazz
{
\"jazzing $_\"
$sum = $sum + $_
}
function foo
{
write-output \"foo executed\"
function innerfoo1 {\"innerfoo1 executed\"}
function innerfoo2 {\"innerfoo2 executed\"}
}
function hello
{
\"hello world\"
}
PS> # chargons la fonction bar (iex est un alias pour invoke-expression) :
PS> $bar = .\get-function f2.ps1 bar
PS> iex $bar
PS> # la fonction est maintenant chargée et disponible, exécutons-la :
PS> bar
bar executed
function:bar
PS> # faisons de même avec la fonction foo :
PS> $foo = .\get-function f2.ps1 foo
PS> iex $foo
PS> foo
foo executed
PS> # essayons avec la fonction innerfoo2, déclarée dans la fonction foo :
PS> innerfoo2
The term 'innerfoo2' 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:10
+ innerfoo2 <<<<
+ CategoryInfo : ObjectNotFound: (innerfoo2:«»String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS> # ... ça ne marche pas, car les deux fonctions
PS> # ... innerfoo1 et innerfoo2 sont privées.
PS> # mais essayons de charger directement innerfoo1 :
PS> $if1 = .\get-function f2.ps1 innerfoo1
PS> iex $if1
PS> # et maintenant exécutons-la :
PS> innerfoo1
innerfoo1 executed
PS> # ... ça marche !
[/code:1]
Et voilà. En espérant que ça vous sera utile.
Janel
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
Réduire
Plus d'informations
- Messages : 6311
- Remerciements reçus 68
il y a 17 ans 3 semaines #4171
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet Re:[script] extraire une fonction d'un script
janel écrit:
De mon coté je pensais l'utiliser afin de générer des scripts de tests permettant validant la gestion des paramètres d'un script PS V1. Cela permettra aussi de manipuler le code comme des données.
Cette API est vraiment un bon apport, elle existait déjà en V1 mais en accès privé.Attention: ce script s'appuie sur une fonctionnalité apparue avec la v2 CTP communément appelée \"Tokenizer API\". Cette API permet d'énumérer les différents éléments syntaxiques d'un script.
De mon coté je pensais l'utiliser afin de générer des scripts de tests permettant validant la gestion des paramètres d'un script PS V1. Cela permettra aussi de manipuler le code comme des données.
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
Temps de génération de la page : 0.074 secondes
- Vous êtes ici :
-
Accueil
-
forum
-
PowerShell
-
Contributions à la communauté
- [script] extraire une fonction d'un script