about_Pipelines

Description courte

Combinaison de commandes dans des pipelines dans PowerShell

Description longue

Un pipeline est une série de commandes connectées par les opérateurs de pipeline (|) (ASCII 124). Chaque opérateur de pipeline envoie les résultats de la commande précédente à la commande suivante.

La sortie de la première commande peut être envoyée pour le traitement en tant qu’entrée à la deuxième commande. Et cette sortie peut être envoyée à une autre commande. Le résultat est une chaîne de commandes ou un pipeline complexe composé d’une série de commandes simples.

Par exemple,

Command-1 | Command-2 | Command-3

Dans cet exemple, les objets émis Command-1 sont envoyés à Command-2. Command-2 traite les objets et les envoie à Command-3. Command-3 traite les objets et les envoie vers le bas du pipeline. Étant donné qu’il n’y a plus de commandes dans le pipeline, les résultats sont affichés sur la console.

Dans un pipeline, les commandes sont traitées dans l’ordre de gauche à droite. Le traitement est géré en tant qu’opération unique et la sortie s’affiche à mesure qu’elle est générée.

Voici un exemple simple. La commande suivante obtient le processus Bloc-notes Windows, puis l’arrête.

Par exemple,

Get-Process notepad | Stop-Process

La première commande utilise l’applet Get-Process de commande pour obtenir un objet représentant le processus Bloc-notes Windows. Il utilise un opérateur de pipeline (|) pour envoyer l’objet de processus à l’applet Stop-Process de commande, ce qui arrête le processus de Bloc-notes Windows. Notez que la Stop-Process commande n’a pas de paramètre Name ou ID pour spécifier le processus, car le processus spécifié est envoyé via le pipeline.

Cet exemple de pipeline obtient les fichiers texte dans le répertoire actif, sélectionne uniquement les fichiers qui sont de plus de 10 000 octets, les trie par longueur et affiche le nom et la longueur de chaque fichier d’une table.

Get-ChildItem -Path *.txt |
  Where-Object {$_.length -gt 10000} |
    Sort-Object -Property length |
      Format-Table -Property name, length

Ce pipeline se compose de quatre commandes dans l’ordre spécifié. L’illustration suivante montre la sortie de chaque commande à mesure qu’elle est passée à la commande suivante dans le pipeline.

Get-ChildItem -Path *.txt
| (FileInfo objects for *.txt)
V
Where-Object {$_.length -gt 10000}
| (FileInfo objects for *.txt)
| (      Length > 10000      )
V
Sort-Object -Property Length
| (FileInfo objects for *.txt)
| (      Length > 10000      )
| (     Sorted by length     )
V
Format-Table -Property name, length
| (FileInfo objects for *.txt)
| (      Length > 10000      )
| (     Sorted by length     )
| (   Formatted in a table   )
V

Name                       Length
----                       ------
tmp1.txt                    82920
tmp2.txt                   114000
tmp3.txt                   114000

Utilisation de pipelines

La plupart des applets de commande PowerShell sont conçues pour prendre en charge les pipelines. Dans la plupart des cas, vous pouvez diriger les résultats d’une applet de commande Get vers une autre applet de commande du même nom. Par exemple, vous pouvez diriger la sortie de l’applet Get-Service de commande vers les Start-Service applets de commande ou Stop-Service les applets de commande.

Cet exemple de pipeline démarre le service WMI sur l’ordinateur :

Get-Service wmi | Start-Service

Pour un autre exemple, vous pouvez diriger la sortie du fournisseur de Registre PowerShell vers Get-ChildItem l’applet New-ItemProperty de Get-Item commande. Cet exemple ajoute une nouvelle entrée de Registre, NoOfEmployees, avec la valeur 8124, à la clé de Registre MyCompany .

Get-Item -Path HKLM:\Software\MyCompany |
  New-ItemProperty -Name NoOfEmployees -Value 8124

La plupart des applets de commande de l’utilitaire, telles que Get-Member, , Where-ObjectSort-Object, , Group-Objectet Measure-Object sont utilisées presque exclusivement dans les pipelines. Vous pouvez diriger n’importe quel type d’objet vers ces applets de commande. Cet exemple montre comment trier tous les processus sur l’ordinateur en fonction du nombre de handles ouverts dans chaque processus.

Get-Process | Sort-Object -Property handles

Vous pouvez diriger des objets vers les applets de commande de mise en forme, d’exportation et de sortie, telles que Format-List, , Format-TableExport-Clixml, Export-CSV, et Out-File.

Cet exemple montre comment utiliser l’applet Format-List de commande pour afficher une liste de propriétés pour un objet de processus.

Get-Process winlogon | Format-List -Property *

Vous pouvez également diriger la sortie des commandes natives vers les applets de commande PowerShell. Par exemple :

PS> ipconfig.exe | Select-String -Pattern 'IPv4'

   IPv4 Address. . . . . . . . . . . : 172.24.80.1
   IPv4 Address. . . . . . . . . . . : 192.168.1.45
   IPv4 Address. . . . . . . . . . . : 100.64.108.37

Important

Les flux Réussite et Erreur sont similaires aux flux stdin et stderr d’autres shells. Toutefois, stdin n’est pas connecté au pipeline PowerShell pour l’entrée. Pour plus d’informations, consultez about_Redirection.

Avec un peu de pratique, vous constaterez que la combinaison de commandes simples dans des pipelines permet de gagner du temps et de taper, ce qui rend votre script plus efficace.

Fonctionnement des pipelines

Cette section explique comment les objets d’entrée sont liés aux paramètres d’applet de commande et traités pendant l’exécution du pipeline.

Accepte l’entrée de pipeline

Pour prendre en charge le pipeline, l’applet de commande de réception doit avoir un paramètre qui accepte l’entrée de pipeline. Utilisez la Get-Help commande avec les options Full ou Parameter pour déterminer quels paramètres d’une applet de commande acceptent l’entrée de pipeline.

Par exemple, pour déterminer quels paramètres de l’applet Start-Service de commande acceptent l’entrée de pipeline, tapez :

Get-Help Start-Service -Full

or

Get-Help Start-Service -Parameter *

L’aide de l’applet Start-Service de commande indique que seuls les paramètres InputObject et Name acceptent l’entrée de pipeline.

-InputObject <ServiceController[]>
Specifies ServiceController objects representing the services to be started.
Enter a variable that contains the objects, or type a command or expression
that gets the objects.

Required?                    true
Position?                    0
Default value                None
Accept pipeline input?       True (ByValue)
Accept wildcard characters?  false

-Name <String[]>
Specifies the service names for the service to be started.

The parameter name is optional. You can use Name or its alias, ServiceName,
or you can omit the parameter name.

Required?                    true
Position?                    0
Default value                None
Accept pipeline input?       True (ByPropertyName, ByValue)
Accept wildcard characters?  false

Lorsque vous envoyez des objets via le pipeline Start-Service, PowerShell tente d’associer les objets aux paramètres InputObject et Name .

Méthodes d’acceptation de l’entrée de pipeline

Les paramètres des applets de commande peuvent accepter l’entrée de pipeline de deux façons différentes :

  • ByValue : Le paramètre accepte les valeurs qui correspondent au type .NET attendu ou qui peuvent être converties en ce type.

    Par exemple, le paramètre Name d’accepte l’entrée de Start-Service pipeline par valeur. Il peut accepter des objets de chaîne ou des objets qui peuvent être convertis en chaînes.

  • ByPropertyName : le paramètre accepte l’entrée uniquement lorsque l’objet d’entrée a une propriété du même nom que le paramètre.

    Par exemple, le paramètre Name de Start-Service peut accepter des objets qui ont une propriété Name . Pour répertorier les propriétés d’un objet, dirigez-le vers Get-Member.

Certains paramètres peuvent accepter des objets par valeur ou par nom de propriété, ce qui facilite la prise en charge de l’entrée à partir du pipeline.

Liaison de paramètres

Lorsque vous dirigez des objets d’une commande vers une autre commande, PowerShell tente d’associer les objets redirigés à un paramètre de l’applet de commande de réception.

Le composant de liaison de paramètres de PowerShell associe les objets d’entrée aux paramètres d’applet de commande en fonction des critères suivants :

  • Le paramètre doit accepter l’entrée d’un pipeline.
  • Le paramètre doit accepter le type d’objet envoyé ou un type qui peut être converti en type attendu.
  • Le paramètre n’a pas été utilisé dans la commande.

Par exemple, l’applet Start-Service de commande a de nombreux paramètres, mais seulement deux d’entre eux, Name et InputObject acceptent l’entrée de pipeline. Le paramètre Name prend des chaînes et le paramètre InputObject prend des objets de service. Par conséquent, vous pouvez diriger des chaînes, des objets de service et des objets avec des propriétés qui peuvent être converties en objets de chaîne ou de service.

PowerShell gère la liaison de paramètres aussi efficacement que possible. Vous ne pouvez pas suggérer ou forcer PowerShell à établir une liaison à un paramètre spécifique. La commande échoue si PowerShell ne peut pas lier les objets redirigés.

Pour plus d’informations sur la résolution des erreurs de liaison, consultez Examen des erreurs de pipeline plus loin dans cet article.

Traitement à usage unique

Les objets de piping vers une commande ressemblent beaucoup à l’utilisation d’un paramètre de la commande pour envoyer les objets. Examinons un exemple de pipeline. Dans cet exemple, nous utilisons un pipeline pour afficher une table d’objets de service.

Get-Service | Format-Table -Property Name, DependentServices

Fonctionnellement, il s’agit de l’utilisation du paramètre InputObject de l’envoi de Format-Table la collection d’objets.

Par exemple, nous pouvons enregistrer la collection de services dans une variable passée à l’aide du paramètre InputObject .

$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices

Ou nous pouvons incorporer la commande dans le paramètre InputObject .

Format-Table -InputObject (Get-Service) -Property Name, DependentServices

Toutefois, il y a une différence importante. Lorsque vous dirigez plusieurs objets vers une commande, PowerShell envoie les objets à la commande une par une. Lorsque vous utilisez un paramètre de commande, les objets sont envoyés en tant qu’objet de tableau unique. Cette différence mineure a des conséquences significatives.

Lors de l’exécution d’un pipeline, PowerShell énumère automatiquement tout type qui implémente l’interface IEnumerable ou son équivalent générique. Les éléments énumérés sont envoyés via le pipeline un par un. PowerShell énumère également les types System.Data.DataTable via la Rows propriété.

Il existe quelques exceptions à l’énumération automatique.

  • Vous devez appeler la méthode pour les GetEnumerator() tables de hachage, les types qui implémentent l’interface IDictionary ou son équivalent générique et les types System.Xml.XmlNode .
  • La classe System.String implémente IEnumerable, mais PowerShell n’énumère pas les objets de chaîne.

Dans les exemples suivants, un tableau et une table de hachage sont redirigés vers l’applet Measure-Object de commande pour compter le nombre d’objets reçus à partir du pipeline. Le tableau a plusieurs membres et la table de hachage a plusieurs paires clé-valeur. Seul le tableau est énuméré un à la fois.

@(1,2,3) | Measure-Object
Count    : 3
Average  :
Sum      :
Maximum  :
Minimum  :
Property :
@{"One"=1;"Two"=2} | Measure-Object
Count    : 1
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

De même, si vous dirigez plusieurs objets de processus de l’applet Get-Process de commande vers l’applet Get-Member de commande, PowerShell envoie chaque objet de processus, un par un à la fois, à Get-Member. Get-Member affiche la classe .NET (type) des objets de processus, ainsi que leurs propriétés et méthodes.

Get-Process | Get-Member
TypeName: System.Diagnostics.Process

Name      MemberType     Definition
----      ----------     ----------
Handles   AliasProperty  Handles = Handlecount
Name      AliasProperty  Name = ProcessName
NPM       AliasProperty  NPM = NonpagedSystemMemorySize
...

Remarque

Get-Member élimine les doublons. Par conséquent, si les objets sont tous du même type, il n’affiche qu’un seul type d’objet.

Toutefois, si vous utilisez le paramètre InputObject de Get-Member, Get-Member reçoit un tableau d’objets System.Diagnostics.Process en tant qu’unité unique. Il affiche les propriétés d’un tableau d’objets. (Notez le symbole du tableau ([]) après le nom du type System.Object .)

Par exemple,

Get-Member -InputObject (Get-Process)
TypeName: System.Object[]

Name               MemberType    Definition
----               ----------    ----------
Count              AliasProperty Count = Length
Address            Method        System.Object& Address(Int32 )
Clone              Method        System.Object Clone()
...

Ce résultat peut ne pas être ce que vous avez prévu. Mais après avoir compris, vous pouvez l’utiliser. Par exemple, tous les objets de tableau ont une propriété Count . Vous pouvez l’utiliser pour compter le nombre de processus en cours d’exécution sur l’ordinateur.

Par exemple,

(Get-Process).count

Il est important de se rappeler que les objets envoyés vers le bas du pipeline sont remis un par un.

Utilisation de commandes natives dans le pipeline

PowerShell vous permet d’inclure des commandes externes natives dans le pipeline. Toutefois, il est important de noter que le pipeline de PowerShell est orienté objet et ne prend pas en charge les données d’octet brutes.

Le piping ou la redirection de sortie à partir d’un programme natif qui génère des données d’octet brutes convertit la sortie en chaînes .NET. Cette conversion peut entraîner une altération de la sortie de données brutes.

Toutefois, PowerShell 7.4 a ajouté la fonctionnalité expérimentale qui préserve les données de flux d’octets lors de la redirection du flux stdout d’une commande native vers un fichier ou lors de la PSNativeCommandPreserveBytePipe redirection des données de flux d’octets vers le flux stdin d’une commande native.

Par exemple, à l’aide de la commande native curl, vous pouvez télécharger un fichier binaire et l’enregistrer sur le disque à l’aide de la redirection.

$uri = 'https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-7.3.4-linux-arm64.tar.gz'

# native command redirected to a file
curl -s -L $uri > powershell.tar.gz

Vous pouvez également diriger les données de flux d’octets vers le flux stdin d’une autre commande native. L’exemple suivant télécharge un fichier TAR compressé à l’aide de curl. Les données du fichier téléchargé sont diffusées en continu vers la commande tar pour extraire le contenu de l’archive.

# native command output piped to a native command
curl -s -L $uri | tar -xzvf - -C .

Vous pouvez également diriger la sortie de flux d’octets d’une commande PowerShell vers l’entrée de la commande native. Les exemples suivants utilisent Invoke-WebRequest pour télécharger le même fichier TAR que l’exemple précédent.

# byte stream piped to a native command
(Invoke-WebRequest $uri).Content | tar -xzvf - -C .

# bytes piped to a native command (all at once as byte[])
,(Invoke-WebRequest $uri).Content | tar -xzvf - -C .

Cette fonctionnalité ne prend pas en charge les données de flux d’octets lors de la redirection de la sortie stderr vers stdout. Lorsque vous combinez les flux stderr et stdout, les flux combinés sont traités comme des données de chaîne.

Examen des erreurs de pipeline

Lorsque PowerShell ne peut pas associer les objets redirigés à un paramètre de l’applet de commande de réception, la commande échoue.

Dans l’exemple suivant, nous essayons de déplacer une entrée de Registre d’une clé de Registre vers une autre. L’applet Get-Item de commande obtient le chemin de destination, qui est ensuite redirigé vers l’applet de Move-ItemProperty commande. La Move-ItemProperty commande spécifie le chemin d’accès actuel et le nom de l’entrée de Registre à déplacer.

Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product

La commande échoue et PowerShell affiche le message d’erreur suivant :

Move-ItemProperty : The input object can't be bound to any parameters for
the command either because the command doesn't take pipeline input or the
input and its properties do not match any of the parameters that take
pipeline input.
At line:1 char:23
+ $a | Move-ItemProperty <<<<  -Path HKLM:\Software\MyCompany\design -Name p

Pour examiner, utilisez l’applet Trace-Command de commande pour suivre le composant de liaison de paramètre de PowerShell. L’exemple suivant trace la liaison de paramètre pendant l’exécution du pipeline. Le paramètre PSHost affiche les résultats de trace dans la console et le paramètre FilePath envoient les résultats de la trace au debug.txt fichier pour référence ultérieure.

Trace-Command -Name ParameterBinding -PSHost -FilePath debug.txt -Expression {
  Get-Item -Path HKLM:\Software\MyCompany\sales |
    Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
}

Les résultats de la trace sont longs, mais affichent les valeurs liées à l’applet Get-Item de commande, puis les valeurs nommées liées à l’applet Move-ItemProperty de commande.

...
BIND NAMED cmd line args [`Move-ItemProperty`]
BIND arg [HKLM:\Software\MyCompany\design] to parameter [Path]
...
BIND arg [product] to parameter [Name]
...
BIND POSITIONAL cmd line args [`Move-ItemProperty`]
...

Enfin, il indique que la tentative de liaison du chemin d’accès au paramètre Destination d’échec Move-ItemProperty .

...
BIND PIPELINE object to parameters: [`Move-ItemProperty`]
PIPELINE object TYPE = [Microsoft.Win32.RegistryKey]
RESTORING pipeline parameter's original values
Parameter [Destination] PIPELINE INPUT ValueFromPipelineByPropertyName NO
COERCION
Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO
COERCION
...

Utilisez l’applet Get-Help de commande pour afficher les attributs du paramètre Destination .

Get-Help Move-ItemProperty -Parameter Destination

-Destination <String>
    Specifies the path to the destination location.

    Required?                    true
    Position?                    1
    Default value                None
    Accept pipeline input?       True (ByPropertyName)
    Accept wildcard characters?  false

Les résultats montrent que la destination accepte uniquement l’entrée de pipeline « par nom de propriété ». Par conséquent, l’objet redirigé doit avoir une propriété nommée Destination.

Permet Get-Member de voir les propriétés de l’objet provenant Get-Itemde .

Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member

La sortie indique que l’élément est un objet Microsoft.Win32.RegistryKey qui n’a pas de propriété Destination . Cela explique pourquoi la commande a échoué.

Le paramètre Path accepte l’entrée de pipeline par nom ou par valeur.

Get-Help Move-ItemProperty -Parameter Path

-Path <String[]>
    Specifies the path to the current location of the property. Wildcard
    characters are permitted.

    Required?                    true
    Position?                    0
    Default value                None
    Accept pipeline input?       True (ByPropertyName, ByValue)
    Accept wildcard characters?  true

Pour corriger la commande, nous devons spécifier la destination dans l’applet Move-ItemProperty de commande et l’utiliser Get-Item pour obtenir le chemin d’accès de l’élément que nous voulons déplacer.

Par exemple,

Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product

Continuation de ligne intrinsèque

Comme indiqué précédemment, un pipeline est une série de commandes connectées par les opérateurs de pipeline (|), généralement écrites sur une seule ligne. Toutefois, pour une lisibilité, PowerShell vous permet de fractionner le pipeline sur plusieurs lignes. Lorsqu’un opérateur de canal est le dernier jeton sur la ligne, l’analyseur PowerShell joint la ligne suivante à la commande actuelle pour continuer la construction du pipeline.

Par exemple, le pipeline à ligne unique suivant :

Command-1 | Command-2 | Command-3

peut être écrit comme suit :

Command-1 |
    Command-2 |
    Command-3

Les espaces de début sur les lignes suivantes ne sont pas significatifs. La mise en retrait améliore la lisibilité.

PowerShell 7 ajoute la prise en charge de la continuation des pipelines avec le caractère de pipeline au début d’une ligne. Les exemples suivants montrent comment utiliser cette nouvelle fonctionnalité.

# Wrapping with a pipe at the beginning of a line (no backtick required)
Get-Process | Where-Object CPU | Where-Object Path
    | Get-Item | Where-Object FullName -match "AppData"
    | Sort-Object FullName -Unique

# Wrapping with a pipe on a line by itself
Get-Process | Where-Object CPU | Where-Object Path
    |
    Get-Item | Where-Object FullName -match "AppData"
    |
    Sort-Object FullName -Unique

Important

Lorsque vous travaillez de manière interactive dans l’interpréteur de commandes, collez du code avec des pipelines au début d’une ligne uniquement lorsque vous utilisez Ctrl+V pour coller. Les opérations de collage avec le bouton droit insèrent les lignes une à la fois. Étant donné que la ligne ne se termine pas par un caractère de pipeline, PowerShell considère que l’entrée est terminée et exécute cette ligne comme entrée.

Voir aussi