web-dev-qa-db-fra.com

comment exporter une classe dans le module powershell v5

J'ai une configuration de module qui ressemble à une bibliothèque pour quelques autres scripts. Je n'arrive pas à comprendre comment obtenir une déclaration de classe dans la portée du script en appelant Import-Module. J'ai essayé d'organiser Export-Module avec un argument -class, comme le -function, mais il n'y a pas de -class disponible. Dois-je simplement déclarer la classe dans chaque script?

La mise en place:

  • holidays.psm1 dans ~\documents\windows\pouvoirs\modules\vacances \
  • appels de script actifs import-module holidays
  • il existe une autre fonction dans holidays.psm1 qui renvoie correctement un objet de classe, mais je ne sais pas comment créer de nouveaux membres de la classe à partir du script actif après l'importation.

Voici à quoi ressemble la classe:

Class data_block
{
    $array
    $rows
    $cols
    data_block($a,$r,$c)
    {
        $this.array = $a
        $this.rows = $r
        $this.cols = $c
    }
}
16
jason

Selon ici et ici , vous pouvez utiliser les classes définies dans votre module en procédant comme suit dans PowerShell 5:

using module holidays
13
Lars Truijens

J'ai trouvé un moyen de charger les classes sans avoir besoin d'utiliser "module". Dans votre fichier MyModule.psd1, utilisez la ligne:

ScriptsToProcess = @('Class.ps1')

Et puis mettez vos classes dans le fichier Class.ps1:

class MyClass {}

Mise à jour: Bien que vous n'ayez pas à utiliser "using module MyModule" avec cette méthode, vous devez toujours:

  • Exécuter "en utilisant le module MyModule"
  • Ou lancez "Import-Module MyModule"
  • Ou appelez n’importe quelle fonction de votre module (pour l’importer automatiquement en cours de route)
13
ili

using est sujet aux pièges

Le mot clé using est sujet aux pièges suivants:

  • L'instruction using ne fonctionne pas pour les modules qui ne sont pas dans PSModulePath sauf si vous spécifiez le chemin complet du module dans l'instruction using. Ceci est plutôt surprenant car bien qu’un module soit disponible via Get-Module, l’instruction using peut ne pas fonctionner en fonction du mode de chargement du module.
  • L'instruction using ne peut être utilisée qu'au tout début d'un "script". Aucune combinaison de [scriptblock]::Create() ou New-Module ne semble pouvoir être surmontée. Une chaîne passée à Invoke-Expression semble agir comme une sorte de script autonome; une instruction using au début d'une telle chaîne de travaux. C'est-à-dire que Invoke-Expression "using module $path" peut réussir, mais la portée dans laquelle le contenu du module est mis à disposition semble plutôt impénétrable. Par exemple, si Invoke-Expression "using module $path" est utilisé dans un scriptblock Pester, les classes du module ne sont pas disponibles à partir du même scriptblock Pester.

Les déclarations ci-dessus sont basées sur cet ensemble de tests .

.NewBoundScriptBlock() semble fonctionner de manière fiable

L'appel d'un scriptblock lié au module contenant la classe semble fonctionner de manière fiable pour exporter des instances d'une classe et ne souffre pas des pièges que using fait. Considérons ce module qui contient une classe et a été importé:

New-Module 'ModuleName' { class c {$p = 'some value'} } |
    Import-Module

Invoquer [c]::new() dans un scriptblock lié au module produit un objet de type [c]:

PS C:\> $c = & (Get-Module 'ModuleName').NewBoundScriptBlock({[c]::new()})
PS C:\> $c.p
some value
12
alx9r

J'ai également rencontré plusieurs problèmes concernant les classes PowerShell dans la v5.

J'ai décidé d'utiliser la solution suivante pour le moment, car elle est parfaitement compatible avec .net et PowerShell:

Add-Type -Language CSharp -TypeDefinition @"
namespace My.Custom.Namespace {
    public class Example
    {
        public string Name { get; set; }
        public System.Management.Automation.PSCredential Credential { get; set; }
        // ...
    }
}
"@

L'avantage est que vous n'avez pas besoin d'un assembly personnalisé pour ajouter une définition de type, vous pouvez ajouter la définition de classe en ligne dans vos scripts ou modules PowerShell. 

Le seul inconvénient est que vous devrez créer un nouveau runtime pour recharger la définition de classe une fois qu'il a été chargé pour la première fois (comme pour le chargement d'assemblys dans un domaine c #/.net).

3
oɔɯǝɹ

Vous ne pouvez pas beaucoup. Selon about_Classes help:

Mot clé de classe

Définit une nouvelle classe. C'est un vrai type .NET Framework. Les membres de classe sont publics, mais uniquement dans la portée du module. Vous ne pouvez pas faire référence au nom du type en tant que chaîne (par exemple, New-Object ne fonctionne pas), et dans cette version, vous ne pouvez pas utiliser de type littéral (par exemple, [MyClass]) en dehors du script/fichier de module dans lequel la classe est définie.

Cela signifie que si vous souhaitez obtenir vous-même une instance data_block ou utiliser des fonctions qui exploitent ces classes, créez une fonction, par exemple, New-DataBlock et faites-lui renvoyer une nouvelle instance data_block, que vous pourrez ensuite utiliser pour obtenir des méthodes et des propriétés de classe ceux statiques).

3
Vesper

Cela ne fonctionne certainement pas comme prévu.
L’idée de PS 5 est que vous pouvez définir votre classe dans un fichier séparé portant l’extension .psm1.
Ensuite, vous pouvez charger la définition avec la commande (par exemple):

   using module C:\classes\whatever\path\to\file.psm1

Ce doit être la première ligne de votre script (après les commentaires).


Ce qui cause tant de peine, c'est que même si les définitions de classe sont appelées à partir d'un script, les modules sont chargés pour toute la session. Vous pouvez le voir en lançant:

    get-module

Vous verrez le nom du fichier que vous avez chargé. Peu importe si vous exécutez le script à nouveau, ilNOTne rechargera pas les définitions de classe! (Ne lira même pas le fichier psm1.) Cela provoque beaucoup de grincements de dents.


Parfois - parfois - vous pouvez exécuter cette commande avant d'exécuter le script, ce qui rechargera le module avec les définitions de classe actualisées:

    remove-module  file

où fichier est le nom sans chemin ni extension. Cependant, pour préserver votre santé, je vous recommande de redémarrer la session PS. C'est évidemment encombrant; Microsoft doit en quelque sorte nettoyer cela.

3
0xG

Pour mettre à jour les définitions de classe en cours de développement, sélectionnez le code de la classe et appuyez sur F8 pour exécuter le code sélectionné. Pas aussi propre que l'option -Force de la commande Import-Module. Voir comme utiliser Module n'a pas cette option et Remove-Module est au mieux sporadique, c'est le meilleur moyen que j'ai trouvé pour développer une classe et voir les résultats sans avoir à fermer ISE et à le redémarrer.

1
DavSum

La déclaration using est la voie à suivre si cela fonctionne pour vous. sinon, cela semble fonctionner aussi.

testclass.psm1

Utiliser une fonction pour donner la classe

class abc{
    $testprop = 'It Worked!'
    [int]testMethod($num){return  $num * 5}
}

function abc(){
    return [abc]::new()
}

Export-ModuleMember -Function abc

someScript.ps1

Import-Module path\to\testclass.psm1
$testclass = abc
$testclass.testProp        # returns 'It Worked!'
$testclass.testMethod(500) # returns 2500


$testclass | gm

Name        MemberType Definition
----        ---------- ----------
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()
GetType     Method     type GetType()
testMethod  Method     int testMethod(System.Object num)
ToString    Method     string ToString()
testprop    Property   System.Object testprop {get;set;}
1
Jakobii

Pour résoudre ce problème, j'ai déplacé votre définition de classe personnalisée dans un fichier .ps1 vide portant le même nom (comme dans Java/C #), puis chargé à la fois dans la définition du module et dans votre code dépendant. sourcing de points. Je sais que ce n'est pas génial, mais pour moi, c'est mieux que de devoir gérer plusieurs définitions de la même classe dans plusieurs fichiers ...

1
Steve Rathbone

J'ai essayé toutes les approches de cette page et j’ai ENCORE cherché une solution qui fonctionne à plusieurs reprises. Je trouve que la mise en cache des modules est l'aspect le plus frustrant de cette opération ... Je peux importer des classes en tant que modules et même faire fonctionner le code, mais powershell ne reconnaît que la nouvelle classe par intermittence ... c'est presque comme si Powershell vous en avait jamais ajouté une .. .

0
user5855178