Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Brève description
Décrit comment utiliser des classes pour créer vos propres types personnalisés.
Description longue
PowerShell 5.0 ajoute une syntaxe formelle pour définir des classes et d’autres types définis par l’utilisateur. L’ajout de classes permet aux développeurs et aux professionnels de l’informatique d’adopter PowerShell pour un plus large éventail de cas d’usage. Il simplifie le développement d’artefacts PowerShell et accélère la couverture des surfaces de gestion.
Une déclaration de classe est un blueprint utilisé pour créer des instances d’objets au moment de l’exécution. Lorsque vous définissez une classe, le nom de la classe est le nom du type. Par exemple, si vous déclarez une classe nommée Device et initialisez une variable $dev à une nouvelle instance de Device, $dev est un objet ou une instance de type Device. Chaque instance de Device peut avoir des valeurs différentes dans ses propriétés.
Scénarios pris en charge
- Définissez des types personnalisés dans PowerShell à l’aide d’une sémantique de programmation orientée objet familière comme les classes, les propriétés, les méthodes, l’héritage, etc.
- Déboguer les types à l’aide du langage PowerShell.
- Générez et gérez des exceptions à l’aide de mécanismes formels.
- Définissez les ressources DSC et leurs types associés à l’aide du langage PowerShell.
Syntaxe
Les classes sont déclarées à l’aide de la syntaxe suivante :
class <class-name> [: [<base-class>][,<interface-list]] {
[[<attribute>] [hidden] [static] <property-definition> ...]
[<class-name>([<constructor-argument-list>])
{<constructor-statement-list>} ...]
[[<attribute>] [hidden] [static] <method-definition> ...]
}
Les classes sont instanciées à l’aide de l’une des syntaxes suivantes :
[$<variable-name> =] New-Object -TypeName <class-name> [
[-ArgumentList] <constructor-argument-list>]
[$<variable-name> =] [<class-name>]::new([<constructor-argument-list>])
Remarque
Lorsque vous utilisez la syntaxe [<class-name>]::new(, les crochets autour du nom de classe sont obligatoires. Les crochets signalent une définition de type pour PowerShell.
Exemple de syntaxe et d’utilisation
Cet exemple montre la syntaxe minimale nécessaire pour créer une classe utilisable.
class Device {
[string]$Brand
}
$dev = [Device]::new()
$dev.Brand = "Microsoft"
$dev
Brand
-----
Microsoft
Propriétés de classe
Les propriétés sont des variables déclarées à la portée de la classe. Une propriété peut être de n’importe quel type intégré ou d’une instance d’une autre classe. Les classes n’ont aucune restriction quant au nombre de propriétés qu’elles possèdent.
Exemple de classe avec des propriétés simples
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
}
$device = [Device]::new()
$device.Brand = "Microsoft"
$device.Model = "Surface Pro 4"
$device.VendorSku = "5072641000"
$device
Brand Model VendorSku
----- ----- ---------
Microsoft Surface Pro 4 5072641000
Exemples de types complexes dans les propriétés de classe
Cet exemple définit une classe Rack vide à l’aide de la classe Device . Les exemples, à la suite de celui-ci, montrent comment ajouter des périphériques au rack et comment commencer avec un rack préchargé.
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
}
class Rack {
[string]$Brand
[string]$Model
[string]$VendorSku
[string]$AssetId
[Device[]]$Devices = [Device[]]::new(8)
}
$rack = [Rack]::new()
$rack
Brand :
Model :
VendorSku :
AssetId :
Devices : {$null, $null, $null, $null...}
Méthodes de classe
Les méthodes définissent les actions qu’une classe peut effectuer. Les méthodes peuvent prendre des paramètres qui fournissent des données d’entrée. Les méthodes peuvent renvoyer une sortie. Les données renvoyées par une méthode peuvent être n’importe quel type de données défini.
Exemple de classe simple avec des propriétés et des méthodes
Extension de la classe Rack pour ajouter et supprimer des périphériques à celle-ci.
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
[string]ToString(){
return ("{0}|{1}|{2}" -f $this.Brand, $this.Model, $this.VendorSku)
}
}
class Rack {
[int]$Slots = 8
[string]$Brand
[string]$Model
[string]$VendorSku
[string]$AssetId
[Device[]]$Devices = [Device[]]::new($this.Slots)
[void] AddDevice([Device]$dev, [int]$slot){
## Add argument validation logic here
$this.Devices[$slot] = $dev
}
[void]RemoveDevice([int]$slot){
## Add argument validation logic here
$this.Devices[$slot] = $null
}
[int[]] GetAvailableSlots(){
[int]$i = 0
return @($this.Devices.foreach{ if($_ -eq $null){$i}; $i++})
}
}
$rack = [Rack]::new()
$surface = [Device]::new()
$surface.Brand = "Microsoft"
$surface.Model = "Surface Pro 4"
$surface.VendorSku = "5072641000"
$rack.AddDevice($surface, 2)
$rack
$rack.GetAvailableSlots()
Slots : 8
Brand :
Model :
VendorSku :
AssetId :
Devices : {$null, $null, Microsoft|Surface Pro 4|5072641000, $null...}
0
1
3
4
5
6
7
Sortie dans les méthodes de classe
Les méthodes doivent avoir un type de retour défini. Si une méthode ne renvoie pas de sortie, le type de sortie doit être [void].
Dans les méthodes de classe, aucun objet n’est envoyé au pipeline, à l’exception de ceux mentionnés dans l’instruction return . Il n’existe aucune sortie accidentelle vers le pipeline à partir du code.
Remarque
Cela diffère fondamentalement de la façon dont les fonctions PowerShell gèrent la sortie, où tout va au pipeline.
Sortie de la méthode
Cet exemple ne montre aucune sortie accidentelle dans le pipeline à partir de méthodes de classe, sauf sur l’instruction return .
class FunWithIntegers
{
[int[]]$Integers = 0..10
[int[]]GetOddIntegers(){
return $this.Integers.Where({ ($_ % 2) })
}
[void] GetEvenIntegers(){
# this following line doesn't go to the pipeline
$this.Integers.Where({ ($_ % 2) -eq 0})
}
[string]SayHello(){
# this following line doesn't go to the pipeline
"Good Morning"
# this line goes to the pipeline
return "Hello World"
}
}
$ints = [FunWithIntegers]::new()
$ints.GetOddIntegers()
$ints.GetEvenIntegers()
$ints.SayHello()
1
3
5
7
9
Hello World
Constructeur
Les constructeurs vous permettent de définir des valeurs par défaut et de valider la logique d’objet au moment de la création de l’instance de la classe. Les constructeurs ont le même nom que la classe. Les constructeurs peuvent avoir des arguments pour initialiser les membres de données du nouvel objet.
La classe peut avoir zéro ou plusieurs constructeurs définis. Si aucun constructeur n’est défini, la classe reçoit un constructeur sans paramètre par défaut. Ce constructeur initialise tous les membres à leurs valeurs par défaut. Les types d’objets et les chaînes reçoivent des valeurs Null. Lorsque vous définissez le constructeur, aucun constructeur sans paramètre par défaut n’est créé. Créez un constructeur sans paramètre si nécessaire.
Syntaxe de base du constructeur
Dans cet exemple, la classe Device est définie avec des propriétés et un constructeur. Pour utiliser cette classe, l’utilisateur doit fournir des valeurs pour les paramètres répertoriés dans le constructeur.
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
Device(
[string]$b,
[string]$m,
[string]$vsk
){
$this.Brand = $b
$this.Model = $m
$this.VendorSku = $vsk
}
}
[Device]$surface = [Device]::new("Microsoft", "Surface Pro 4", "5072641000")
$surface
Brand Model VendorSku
----- ----- ---------
Microsoft Surface Pro 4 5072641000
Exemple avec plusieurs constructeurs
Dans cet exemple, la classe Device est définie avec des propriétés, un constructeur par défaut et un constructeur pour initialiser l’instance.
Le constructeur par défaut définit la marque sur Undefined et laisse model et vendor-sku avec des valeurs nulles.
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
Device(){
$this.Brand = 'Undefined'
}
Device(
[string]$b,
[string]$m,
[string]$vsk
){
$this.Brand = $b
$this.Model = $m
$this.VendorSku = $vsk
}
}
[Device]$somedevice = [Device]::new()
[Device]$surface = [Device]::new("Microsoft", "Surface Pro 4", "5072641000")
$somedevice
$surface
Brand Model VendorSku
----- ----- ---------
Undefined
Microsoft Surface Pro 4 5072641000
Attribut caché
L’attribut hidden rend une propriété ou une méthode moins visible. La propriété ou la méthode est toujours accessible à l’utilisateur et est disponible dans toutes les étendues dans lesquelles l’objet est disponible. Les membres masqués sont masqués dans l’applet Get-Member de commande et ne peuvent pas être affichés à l’aide de la saisie semi-automatique par tabulation ou d’IntelliSense en dehors de la définition de classe.
Exemple d’utilisation d’attributs masqués
Lorsqu’un objet Rack est créé, le nombre d’emplacements pour les périphériques est une valeur fixe qui ne doit être modifiée à aucun moment. Cette valeur est connue au moment de la création.
L’utilisation de l’attribut hidden permet au développeur de garder le nombre d’emplacements cachés et d’éviter les modifications involontaires de la taille du rack.
class Device {
[string]$Brand
[string]$Model
}
class Rack {
[int] hidden $Slots = 8
[string]$Brand
[string]$Model
[Device[]]$Devices = [Device[]]::new($this.Slots)
Rack ([string]$b, [string]$m, [int]$capacity){
## argument validation here
$this.Brand = $b
$this.Model = $m
$this.Slots = $capacity
## reset rack size to new capacity
$this.Devices = [Device[]]::new($this.Slots)
}
}
[Rack]$r1 = [Rack]::new("Microsoft", "Surface Pro 4", 16)
$r1
$r1.Devices.Length
$r1.Slots
Brand Model Devices
----- ----- -------
Microsoft Surface Pro 4 {$null, $null, $null, $null...}
16
16
Notez que la propriété Slots n’est pas affichée dans la $r1 sortie. Cependant, la taille a été modifiée par le constructeur.
Attribut statique
L’attribut static définit une propriété ou une méthode qui existe dans la classe et qui n’a pas besoin d’instance.
Une propriété statique est toujours disponible, indépendamment de l’instanciation de classe. Une propriété statique est partagée entre toutes les instances de la classe. Une méthode statique est toujours disponible. Toutes les propriétés statiques sont actives pour l’ensemble de la session.
Exemple d’utilisation d’attributs et de méthodes statiques
Supposons que les racks instanciés ici existent dans votre centre de données. Vous souhaitez donc garder une trace des racks dans votre code.
class Device {
[string]$Brand
[string]$Model
}
class Rack {
hidden [int] $Slots = 8
static [Rack[]]$InstalledRacks = @()
[string]$Brand
[string]$Model
[string]$AssetId
[Device[]]$Devices = [Device[]]::new($this.Slots)
Rack ([string]$b, [string]$m, [string]$id, [int]$capacity){
## argument validation here
$this.Brand = $b
$this.Model = $m
$this.AssetId = $id
$this.Slots = $capacity
## reset rack size to new capacity
$this.Devices = [Device[]]::new($this.Slots)
## add rack to installed racks
[Rack]::InstalledRacks += $this
}
static [void]PowerOffRacks(){
foreach ($rack in [Rack]::InstalledRacks) {
Write-Warning ("Turning off rack: " + ($rack.AssetId))
}
}
}
Test de l’existence d’une propriété statique et d’une méthode
PS> [Rack]::InstalledRacks.Length
0
PS> [Rack]::PowerOffRacks()
PS> (1..10) | ForEach-Object {
>> [Rack]::new("Adatum Corporation", "Standard-16",
>> $_.ToString("Std0000"), 16)
>> } > $null
PS> [Rack]::InstalledRacks.Length
10
PS> [Rack]::InstalledRacks[3]
Brand Model AssetId Devices
----- ----- ------- -------
Adatum Corporation Standard-16 Std0004 {$null, $null, $null, $null...}
PS> [Rack]::PowerOffRacks()
WARNING: Turning off rack: Std0001
WARNING: Turning off rack: Std0002
WARNING: Turning off rack: Std0003
WARNING: Turning off rack: Std0004
WARNING: Turning off rack: Std0005
WARNING: Turning off rack: Std0006
WARNING: Turning off rack: Std0007
WARNING: Turning off rack: Std0008
WARNING: Turning off rack: Std0009
WARNING: Turning off rack: Std0010
Notez que le nombre de racks augmente à chaque fois que vous exécutez cet exemple.
Attributs de validation de propriété
Les attributs de validation vous permettent de tester que les valeurs données aux propriétés répondent aux exigences définies. La validation est déclenchée au moment où la valeur est affectée. Voir about_functions_advanced_parameters.
Exemple d’utilisation d’attributs de validation
class Device {
[ValidateNotNullOrEmpty()][string]$Brand
[ValidateNotNullOrEmpty()][string]$Model
}
[Device]$dev = [Device]::new()
Write-Output "Testing dev"
$dev
$dev.Brand = ""
Testing dev
Brand Model
----- -----
Exception setting "Brand": "The argument is null or empty. Provide an
argument that is not null or empty, and then try the command again."
At C:\tmp\Untitled-5.ps1:11 char:1
+ $dev.Brand = ""
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Héritage dans les classes PowerShell
Vous pouvez étendre une classe en créant une classe qui dérive d’une classe existante. La classe dérivée hérite des propriétés de la classe de base. Vous pouvez ajouter ou remplacer des méthodes et des propriétés selon vos besoins.
PowerShell ne prend pas en charge l’héritage multiple. Les classes ne peuvent pas hériter de plus d’une classe. Cependant, vous pouvez utiliser des interfaces à cet effet.
L’implémentation de l’héritage est définie par l’opérateur, c’est-à-dire : étendre cette classe ou implémenter ces interfaces. La classe dérivée doit toujours être la plus à gauche dans la déclaration de classe.
Exemple d’utilisation d’une syntaxe d’héritage simple
Cet exemple illustre la syntaxe simple d’héritage de la classe PowerShell.
Class Derived : Base {...}
Cet exemple montre l’héritage avec une déclaration d’interface qui vient après la classe de base.
Class Derived : Base.Interface {...}
Exemple d’héritage simple dans les classes PowerShell
Dans cet exemple, les classes Rack et Device utilisées dans les exemples précédents sont mieux définies pour éviter les répétitions de propriétés, mieux aligner les propriétés communes et réutiliser une logique métier commune.
La plupart des objets du centre de données sont des actifs de l’entreprise, il est donc logique de commencer à les suivre en tant qu’actifs. Les types d’appareils sont définis par l’énumération, DeviceType about_Enum pour plus d’informations sur les énumérations.
Dans notre exemple, nous définissons Rack uniquement et ComputeServer, les deux extensions de la Device classe.
enum DeviceType {
Undefined = 0
Compute = 1
Storage = 2
Networking = 4
Communications = 8
Power = 16
Rack = 32
}
class Asset {
[string]$Brand
[string]$Model
}
class Device : Asset {
hidden [DeviceType]$devtype = [DeviceType]::Undefined
[string]$Status
[DeviceType] GetDeviceType(){
return $this.devtype
}
}
class ComputeServer : Device {
hidden [DeviceType]$devtype = [DeviceType]::Compute
[string]$ProcessorIdentifier
[string]$Hostname
}
class Rack : Device {
hidden [DeviceType]$devtype = [DeviceType]::Rack
hidden [int]$Slots = 8
[string]$Datacenter
[string]$Location
[Device[]]$Devices = [Device[]]::new($this.Slots)
Rack (){
## Just create the default rack with 8 slots
}
Rack ([int]$s){
## Add argument validation logic here
$this.Devices = [Device[]]::new($s)
}
[void] AddDevice([Device]$dev, [int]$slot){
## Add argument validation logic here
$this.Devices[$slot] = $dev
}
[void] RemoveDevice([int]$slot){
## Add argument validation logic here
$this.Devices[$slot] = $null
}
}
$FirstRack = [Rack]::new(16)
$FirstRack.Status = "Operational"
$FirstRack.Datacenter = "PNW"
$FirstRack.Location = "F03R02.J10"
(0..15).ForEach({
$ComputeServer = [ComputeServer]::new()
$ComputeServer.Brand = "Fabrikam, Inc." ## Inherited from Asset
$ComputeServer.Model = "Fbk5040" ## Inherited from Asset
$ComputeServer.Status = "Installed" ## Inherited from Device
$ComputeServer.ProcessorIdentifier = "x64" ## ComputeServer
$ComputeServer.Hostname = ("r1s" + $_.ToString("000")) ## ComputeServer
$FirstRack.AddDevice($ComputeServer, $_)
})
$FirstRack
$FirstRack.Devices
Datacenter : PNW
Location : F03R02.J10
Devices : {r1s000, r1s001, r1s002, r1s003...}
Status : Operational
Brand :
Model :
ProcessorIdentifier : x64
Hostname : r1s000
Status : Installed
Brand : Fabrikam, Inc.
Model : Fbk5040
ProcessorIdentifier : x64
Hostname : r1s001
Status : Installed
Brand : Fabrikam, Inc.
Model : Fbk5040
<... content truncated here for brevity ...>
ProcessorIdentifier : x64
Hostname : r1s015
Status : Installed
Brand : Fabrikam, Inc.
Model : Fbk5040
Appel de constructeurs de classe de base
Pour appeler un constructeur de classe de base à partir d’une sous-classe, ajoutez le mot-clé base .
class Person {
[int]$Age
Person([int]$a)
{
$this.Age = $a
}
}
class Child : Person
{
[string]$School
Child([int]$a, [string]$s ) : base($a) {
$this.School = $s
}
}
[Child]$littleone = [Child]::new(10, "Silver Fir Elementary School")
$littleone.Age
10
Appeler les méthodes de la classe de base
Pour remplacer les méthodes existantes dans les sous-classes, déclarez les méthodes en utilisant le même nom et la même signature.
class BaseClass
{
[int]days() {return 1}
}
class ChildClass1 : BaseClass
{
[int]days () {return 2}
}
[ChildClass1]::new().days()
2
Pour appeler des méthodes de classe de base à partir d’implémentations remplacées, convertissez en classe de base ([baseclass]$this) lors de l’appel.
class BaseClass
{
[int]days() {return 1}
}
class ChildClass1 : BaseClass
{
[int]days () {return 2}
[int]basedays() {return ([BaseClass]$this).days()}
}
[ChildClass1]::new().days()
[ChildClass1]::new().basedays()
2
1
Interfaces
La syntaxe de déclaration des interfaces est similaire à celle de C#. Vous pouvez déclarer des interfaces après les types de base ou immédiatement après un deux-points (:) lorsqu’aucun type de base n’est spécifié. Séparez tous les noms de type par des virgules.
class MyComparable : system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}
class MyComparableBar : bar, system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}
Importation de classes à partir d’un module PowerShell
Import-Module et l’instruction #requires importent uniquement les fonctions de module, les alias et les variables, comme défini par le module. Les classes ne sont pas importées. L’instruction using module importe les classes définies dans le module. Si le module n’est pas chargé dans la session en cours, l’instruction using échoue.