La sortie texte des commandes dans la fenêtre de l'interpréteur PowerShell n'est qu'un moyen d'afficher les informations de manière compréhensible pour l'homme. En réalité, l'environnement fonctionne avec des objets : les cmdlets et les fonctions reçoivent ces objets en entrée et , tandis que les types de variables disponibles en mode interactif et dans les scripts sont basés sur les classes .NET. Dans le quatrième article de la série, nous examinerons plus en détail le travail avec des objets.
Table des matières :
Objets dans PowerShell
Rappelons qu'un objet est un ensemble de champs de données (propriétés, événements, etc.) et de méthodes permettant de les traiter. Sa structure est définie par un type, qui est généralement basé sur les classes utilisées dans la plateforme unifiée .NET Core. Il est également possible de travailler avec des objets COM, CIM (WMI) et ADSI. Les propriétés et les méthodes sont nécessaires pour effectuer diverses actions sur les données, de plus, dans PowerShell, les objets peuvent être passés comme arguments à des fonctions et des cmdlets, leurs valeurs peuvent être assignées à des variables, et il existe (pipeline). Chaque commande dans le pipeline transmet sa sortie à la suivante, objet par objet. Pour le traitement, des cmdlets compilés peuvent être utilisés ou vous pouvez créer vos propres , pour effectuer diverses manipulations avec des objets dans le pipeline : filtrage, tri, regroupement et même modification de leur structure. Le passage des données de cette manière a un avantage considérable : l'équipe réceptrice n'a pas besoin de se soucier de l'analyse syntaxique du flux d'octets (texte), toutes les informations nécessaires peuvent être facilement extraites en accédant aux propriétés et méthodes appropriées.
Visualisation de la structure des objets
Prenons par exemple le cmdlet Get-Process, qui permet d'obtenir des informations sur les processus en cours d'exécution dans le système :

Il affichera à l'écran certaines données textuelles formatées, ne donnant pas une idée des propriétés des objets retournés et de leurs méthodes. Pour analyser finement la sortie, il faut apprendre à explorer la structure des objets, et le cmdlet Get-Member nous y aidera :
Get-Process | Get-Member 
Ici, nous voyons déjà le type et la structure, et grâce à des paramètres supplémentaires, nous pouvons, par exemple, afficher uniquement les propriétés de l'objet qui est passé en entrée :
Get-Process | Get-Member -MemberType PropertyCes connaissances seront nécessaires pour résoudre des tâches d'administration en mode interactif ou pour écrire vos propres scripts : disons, pour obtenir des informations sur les processus suspendus selon la propriété Responding.
Filtrage des objets
PowerShell permet de passer à travers le pipeline des objets qui satisfont à une condition particulière :
Where-Object { bloc de script }Le résultat de l'exécution du bloc de script entre accolades doit être une valeur logique. Si elle est vraie ($true), l'objet passé au cmdlet Where-Object sera transmis plus loin dans le pipeline, sinon (valeur $false) il sera supprimé. Par exemple, affichons la liste des services Windows Server arrêtés, c'est-à-dire ceux dont la propriété Status a la valeur « Stopped » :
Get-Service | Where-Object {$_.Status -eq "Stopped"} 
Ici, nous voyons à nouveau une représentation textuelle, mais pour ceux qui souhaitent comprendre le type et la structure interne des objets passant par le pipeline, ce n'est pas difficile :
Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member 
Tri des objets
Lors du traitement par pipeline d'objets, il y a souvent un besoin de les trier. Au cmdlet Sort-Object, on passe les noms des propriétés (clés de tri), et il renvoie des objets classés selon leurs valeurs. Il est facile de trier la sortie des processus en cours d'exécution selon le temps processeur utilisé (propriété cpu) :
Get-Process | Sort-Object –Property cpuLe paramètre -Property peut ne pas être spécifié lors de l'appel du cmdlet Sort-Object — il est utilisé par défaut. Pour le tri inverse, on utilise le paramètre -Descending :
Get-Process | Sort-Object cpu -Descending 
Mise en évidence des objets et de leurs parties
Le cmdlet Select-Object permet de sélectionner un certain nombre d'objets au début ou à la fin du pipeline à l'aide des paramètres -First ou -Last. Grâce à lui, vous pouvez choisir des objets uniques ou certaines propriétés, et également créer de nouveaux objets sur cette base. Analysons le fonctionnement du cmdlet avec quelques exemples simples.
La commande suivante affiche des informations sur 10 processus consommant le plus de mémoire vive (propriété WS) :
Get-Process | Sort-Object WS -Descending | Select-Object -First 10 
Il est possible de sélectionner uniquement certaines propriétés des objets passant par le pipeline et de créer de nouveaux objets sur cette base :
Get-Process | Select-Object ProcessName, Id -First 1En raison du traitement du pipeline, nous allons obtenir un nouvel objet dont la structure sera différente de celle retournée par la cmdlet Get-Process. Vérifions cela à l'aide de Get-Member :
Get-Process | Select-Object ProcessName, Id -First 1 | Get-Member 
Notez que Select-Object retourne un seul objet (-First 1), qui n'a que deux champs spécifiés par nos soins : leurs valeurs ont été copiées du premier objet transmis dans le pipeline par la cmdlet Get-Process. L'utilisation de Select-Object est l'une des façons de créer des objets dans les scripts PowerShell :
$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType() 
Avec Select-Object, vous pouvez ajouter des propriétés calculées aux objets, qui doivent être présentées sous forme . Dans ce cas, la valeur de sa première clé correspond au nom de la propriété, et la valeur de la seconde — à la valeur de la propriété pour l'élément actuel du pipeline :
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} 
Examinons la structure des objets passant par le pipeline :
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} | Get-Member 
ForEach-Object, Group-Object et Measure-Object
Il existe d'autres cmdlets pour travailler avec des objets. Par exemple, discutons des trois plus utiles :
ForEach-Object qui permet d'exécuter du code en PowerShell pour chaque objet dans le pipeline :
ForEach-Object { bloc de script }Group-Object qui groupe les objets par valeur de propriété :
Group-Object PropertyNameSi vous l'exécutez avec le paramètre -NoElement, vous pouvez connaître le nombre d'éléments dans les groupes.
Measure-Object qui agrège divers paramètres récapitulatifs selon les valeurs des champs des objets dans le pipeline (calcule la somme, trouve également la valeur minimale, maximale ou moyenne) :
Measure-Object -Property PropertyName -Minimum -Maximum -Average -SumGénéralement, les cmdlets examinées sont utilisées en mode interactif, tandis que dans les scripts, on crée plus fréquemment avec des blocs Begin, Process et End.
Création d'objets .NET et COM (New-Object)
Il existe de nombreux composants logiciels avec des interfaces .NET Core et COM, qui seront utiles aux administrateurs système. Avec la classe System.Diagnostics.EventLog, vous pouvez gérer les journaux système directement depuis Windows PowerShell. Détaillons un exemple de création d'une instance de cette classe avec la cmdlet New-Object et le paramètre -TypeName :
New-Object -TypeName System.Diagnostics.EventLog 
Étant donné que nous n'avons pas spécifié de registre d'événements particulier, l'instance de classe obtenue ne contient pas de données. Pour remédier à cela, il est nécessaire, lors de sa création, d'appeler une méthode de constructeur spéciale à l'aide du paramètre -ArgumentList. Si nous voulons accéder au journal des applications, il faudra passer la chaîne « Application » en tant qu'argument au constructeur :
$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog 
Remarque : la sortie de la commande a été sauvegardée dans la variable $AppLog. Bien que le mode interactif utilise généralement des pipelines, l'écriture de scripts nécessite souvent de conserver une référence à l'objet. De plus, les classes principales de .NET Core se trouvent dans l'espace de noms System : PowerShell les recherche par défaut dans ce dernier pour les types spécifiés, il est donc tout à fait correct d'écrire Diagnostics.EventLog au lieu de System.Diagnostics.EventLog.
Pour travailler avec le registre, on peut utiliser les méthodes correspondantes :
$AppLog | Get-Member -MemberType Method 
Disons qu'il peut être nettoyé avec la méthode Clear() en cas de droits d'accès :
$AppLog.Clear()Le cmdlet New-Object est également utilisé pour travailler avec des composants COM. Il en existe beaucoup — des bibliothèques de scripts Windows livrées avec le serveur aux applications ActiveX, telles que Internet Explorer, par exemple. Pour créer un objet COM, il faut spécifier le paramètre -ComObject avec l'identifiant ProgId de la classe souhaitée :
New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObjectPour créer des objets personnalisés avec une structure arbitraire, l'utilisation de New-Object semble trop archaïque et encombrante, ce cmdlet est utilisé pour travailler avec des composants logiciels externes à PowerShell. Dans les articles suivants, cette question sera examinée plus en détail. En plus des objets .NET et COM, nous allons également étudier les objets CIM (WMI) et ADSI.
Appel de méthodes statiques
Il est impossible de créer des instances de certaines classes .NET Core : parmi celles-ci, on trouve System.Environment et System.Math. Elles sont et contiennent uniquement des propriétés et méthodes statiques. En fait, ce sont des bibliothèques de référence qui sont utilisées sans créer d'objets. On peut faire référence à une classe statique à l'aide d'un littéral, en plaçant le nom du type entre crochets. En regardant la structure de l'objet avec Get-Member, nous verrons le type System.RuntimeType au lieu de System.Environment :
[System.Environment] | Get-Member 
Pour visualiser uniquement des éléments statiques, il faut appeler Get-Member avec le paramètre -Static (notez le type d'objet) :
[System.Environment] | Get-Member -Static 
Pour accéder aux propriétés et méthodes statiques, on utilise deux deux-points consécutifs au lieu d'un point après le littéral :
[System.Environment]::OSVersionOu
$test=[System.Math]::Sqrt(25)
$test
$test.GetType() 
Type PSCustomObject
Parmi les nombreux types de données disponibles dans PowerShell, il convient de mentionner séparément le PSCustomObject, destiné à stocker des objets à structure arbitraire. Créer un tel objet avec la cmdlet New-Object est considéré comme une méthode classique, mais encombrante et obsolète :
$object = New-Object –TypeName PSCustomObject -Property @{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'}
Examinons la structure de l'objet :
$object | Get-Member 
Depuis PowerShell 3.0, une autre syntaxe est également disponible :
$object = [PSCustomObject]@{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'
}
On peut accéder aux données de plusieurs manières équivalentes :
$object.Name
$object.'Name'
$value = 'Name'
$object.$value
Fournissons un exemple de conversion en objet d'une table de hachage existante :
$hash = @{'Name'='Ivan Danko'; 'City'='Moscow'; 'Country'='Russia'}
$hash.GetType()
$object = [pscustomobject]$hash
$object.GetType()

Un des inconvénients de ce type d'objet est que l'ordre de ses propriétés peut changer. Pour éviter cela, il faut utiliser l'attribut [ordered] :
$object = [PSCustomObject][ordered]@{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'
}
Il existe d'autres façons de créer un objet : nous avons vu ci-dessus l'utilisation de la cmdlet . Il reste à comprendre comment ajouter et supprimer des éléments. Pour l'objet de l'exemple précédent, c'est assez simple :
$object | Add-Member –MemberType NoteProperty –Name Age –Value 33
$object | Get-Member

La cmdlet Add-Member permet d'ajouter non seulement des propriétés, mais aussi des méthodes à un objet $object précédemment créé en utilisant la construction "-MemberType ScriptMethod" :
$ScriptBlock = {
# code
}
$object | Add-Member -Name "MyMethod" -MemberType ScriptMethod -Value $ScriptBlock
$object | Get-Member
Notez que pour stocker le code de la nouvelle méthode, nous avons utilisé la variable $ScriptBlock de type ScriptBlock.

Pour supprimer des propriétés, on utilise la méthode correspondante :
$object.psobject.properties.remove('Name')
Création de vos propres classes
Dans PowerShell 5.0, la possibilité de définir en utilisant une syntaxe typique des langages de programmation orientés objet. Pour cela, le mot-clé Class est utilisé, suivi du nom de la classe et de la définition de son corps entre accolades :
class MyClass
{
# corps de la classe
}
C'est un véritable type .NET Core, dont le corps définit ses propriétés, méthodes et autres éléments. Examinons un exemple de définition de classe simple :
class MyClass
{
[string]$Name
[string]$City
[string]$Country
}
Pour créer un objet (instance de la classe), le cmdlet , ou un littéral de type [MyClass] et new (constructeur par défaut) :
$object = New-Object -TypeName MyClassou
$object = [MyClass]::new()Analysons la structure de l'objet :
$object | Get-Member 
Il ne faut pas oublier la portée : il est impossible de faire référence au nom du type sous forme de chaîne ou d'utiliser un littéral de type en dehors du script ou du module dans lequel la classe est définie. Cependant, des fonctions peuvent retourner des instances de classe (objets) qui seront accessibles en dehors du module ou du script.
Après avoir créé l'objet, remplissons ses propriétés :
$object.Name = 'Ivan Danko'
$object.City = 'Moscow'
$object.Country = 'Russia'
$object

Il convient de noter que dans la définition de la classe, on spécifie non seulement les types de propriétés, mais aussi leurs valeurs par défaut :
class Example
{
[string]$Name = 'John Doe'
}
La définition d'une méthode de classe ressemble à celle d'une fonction, mais sans utiliser le mot-clé function. Comme pour une fonction, des paramètres peuvent être passés aux méthodes si nécessaire :
class MyClass
{
[string]$Name
[string]$City
[string]$Country
# définition de la méthode
Smile([bool]$param1)
{
If($param1) {
Write-Host ':)'
}
}
}
Maintenant, un représentant de notre classe sait sourire :
$object = [MyClass]::new()
$object.Smile($true)
Les méthodes peuvent être surchargées, de plus, une classe peut avoir , ainsi que des constructeurs, dont les noms coïncident avec le nom de la classe elle-même. Une classe PowerShell définie dans un script ou un module peut servir de base à une autre — c'est ainsi que s'implémente l'héritage. Dans ce cas, il est permis d'utiliser des classes .NET existantes comme classes de base :
class MyClass2 : MyClass
{
# corps de la nouvelle classe, dont la base est MyClass
}
[MyClass2]::new().Smile($true)
Notre présentation du travail avec des objets dans PowerShell ne peut pas être qualifiée d'exhaustive. Dans les prochaines publications, nous tenterons de l'approfondir avec des exemples pratiques : le cinquième article de la série sera consacré aux questions d'intégration de PowerShell avec des composants logiciels externes. Les parties précédentes peuvent être trouvées aux liens ci-dessous.
Source : habr.com
