Question Dans Powershell, quelle est la meilleure façon de réunir deux tables en une seule?


Je suis assez nouveau sur Powershell et je me demande si quelqu'un connaît un meilleur moyen de résoudre le problème suivant.

J'ai un tableau de mappages depuis une adresse IP vers un nom d'hôte. Ceci représente une liste de baux DHCP actifs:

PS H:\> $leases

IP                    Name
--                    ----
192.168.1.1           Apple
192.168.1.2           Pear
192.168.1.3           Banana
192.168.1.99          FishyPC

J'ai un autre tableau de mappages de l'adresse MAC à l'adresse IP. Ceci représente une liste de réservations IP:

PS H:\> $reservations

IP                    MAC
--                    ---
192.168.1.1           001D606839C2
192.168.1.2           00E018782BE1
192.168.1.3           0022192AF09C
192.168.1.4           0013D4352A0D

Pour plus de commodité, j'ai été en mesure de produire un troisième tableau de mappages à partir de l'adresse MAC vers l'adresse IP et le nom d'hôte à l'aide du code suivant. L'idée est que $reservations devrait avoir un troisième champ, "Nom", qui est renseigné chaque fois qu’il ya un champ "IP" correspondant:

$reservations = $reservations | foreach {
    $res = $_
    $match = $leases | where {$_.IP -eq $res.IP} | select -unique
    if ($match -ne $NULL) {
        "" | select @{n="IP";e={$res.IP}}, @{n="MAC";e={$res.MAC}}, @{n="Name";e={$match.Name}}
    }
}

La sortie souhaitée est quelque chose comme ceci:

PS H:\> $ideal

IP                    MAC                 Name
--                    ---                 ----
192.168.1.1           001D606839C2        Apple
192.168.1.2           00E018782BE1        Pear
192.168.1.3           0022192AF09C        Banana
192.168.1.4           0013D4352A0D

Y a-t-il une meilleure façon de le faire?


10
2017-12-04 18:31


origine


Réponses:


Lee Holmes a écrit un article de blog sur une fonction Join-Object cela fait ce que vous voulez. Dommage qu'il ne soit pas encore intégré à PowerShell.


8
2017-12-04 18:39



Objet de jointure

le Join-Object (alias Join) combine des colonnes de deux tableaux d’objets dans un nouveau tableau d’objets pouvant être enregistré sous forme de tableau (Export-CSV) ou utilisé tel quel.

Function Join-Object {                                          # https://powersnippets.com/join-object/
    [CmdletBinding()]Param (                                    # Version 02.02.00, by iRon
        [Object[]]$RightTable, [Alias("Using")]$On, $Merge = @{}, [Parameter(ValueFromPipeLine = $True)][Object[]]$LeftTable, [String]$Equals
    )
    $Type = ($MyInvocation.InvocationName -Split "-")[0]
    $PipeLine = $Input | ForEach {$_}; If ($PipeLine) {$LeftTable = $PipeLine}
    If ($LeftTable -eq $Null) {If ($RightTable[0] -is [Array]) {$LeftTable = $RightTable[0]; $RightTable = $RightTable[-1]} Else {$LeftTable = $RightTable}}
    $DefaultMerge = If ($Merge -is [ScriptBlock]) {$Merge; $Merge = @{}} ElseIf ($Merge."") {$Merge.""} Else {{$Left.$_, $Right.$_}}
    If ($Equals) {$Merge.$Equals = {If ($Left.$Equals -ne $Null) {$Left.$Equals} Else {$Right.$Equals}}}
    ElseIf ($On -is [String] -or $On -is [Array]) {@($On) | ForEach {If (!$Merge.$_) {$Merge.$_ = {$Left.$_}}}}
    $LeftKeys  = @($LeftTable[0].PSObject.Properties  | ForEach {$_.Name})
    $RightKeys = @($RightTable[0].PSObject.Properties | ForEach {$_.Name})
    $Keys = $LeftKeys + $RightKeys | Select -Unique
    $Keys | Where {!$Merge.$_} | ForEach {$Merge.$_ = $DefaultMerge}
    $Properties = @{}; $LeftOut = @($True) * @($LeftTable).Length; $RightOut = @($True) * @($RightTable).Length
    For ($LeftIndex = 0; $LeftIndex -lt $LeftOut.Length; $LeftIndex++) {$Left = $LeftTable[$LeftIndex]
        For ($RightIndex = 0; $RightIndex -lt $RightOut.Length; $RightIndex++) {$Right = $RightTable[$RightIndex]
            $Select = If ($On -is [String]) {If ($Equals) {$Left.$On -eq $Right.$Equals} Else {$Left.$On -eq $Right.$On}}
            ElseIf ($On -is [Array]) {($On | Where {!($Left.$_ -eq $Right.$_)}) -eq $Null} ElseIf ($On -is [ScriptBlock]) {&$On} Else {$True}
            If ($Select) {$Keys | ForEach {$Properties.$_ = 
                    If ($LeftKeys -NotContains $_) {$Right.$_} ElseIf ($RightKeys -NotContains $_) {$Left.$_} Else {&$Merge.$_}
                }; New-Object PSObject -Property $Properties; $LeftOut[$LeftIndex], $RightOut[$RightIndex] = $Null
    }   }   }
    If ("LeftJoin",  "FullJoin" -Contains $Type) {
        For ($LeftIndex = 0; $LeftIndex -lt $LeftOut.Length; $LeftIndex++) {
            If ($LeftOut[$LeftIndex]) {$Keys | ForEach {$Properties.$_ = $LeftTable[$LeftIndex].$_}; New-Object PSObject -Property $Properties}
    }   }
    If ("RightJoin", "FullJoin" -Contains $Type) {
        For ($RightIndex = 0; $RightIndex -lt $RightOut.Length; $RightIndex++) {
            If ($RightOut[$RightIndex]) {$Keys | ForEach {$Properties.$_ = $RightTable[$RightIndex].$_}; New-Object PSObject -Property $Properties}
    }   }
}; Set-Alias Join   Join-Object
Set-Alias InnerJoin Join-Object; Set-Alias InnerJoin-Object Join-Object -Description "Returns records that have matching values in both tables"
Set-Alias LeftJoin  Join-Object; Set-Alias LeftJoin-Object  Join-Object -Description "Returns all records from the left table and the matched records from the right table"
Set-Alias RightJoin Join-Object; Set-Alias RightJoin-Object Join-Object -Description "Returns all records from the right table and the matched records from the left table"
Set-Alias FullJoin  Join-Object; Set-Alias FullJoin-Object  Join-Object -Description "Returns all records when there is a match in either left or right table"

Syntaxe

<Object[]> | InnerJoin|LeftJoin|RightJoin|FullJoin <Object[]> [-On <String>|<Array>|<ScriptBlock>] [-Merge <HashTable>|<ScriptBlock>] [-Eq <String>]

InnerJoin|LeftJoin|RightJoin|FullJoin <Object[]>,<Object[]> [-On <String>|<Array>|<ScriptBlock>] [-Merge <HashTable>|<ScriptBlock>] [-Eq <String>]

InnerJoin|LeftJoin|RightJoin|FullJoin -LeftTable <Object[]> -RightTable <Object[]> [-On <String>|<Array>|<ScriptBlock>] [-Merge <HashTable>|<ScriptBlock>] [-Eq <String>]

Commandes

le Join-Object (alias Join) fonction est une fonction avec plusieurs alias qui joint deux tables (chacune consistant en un tableau de PSCustomObjects) similaire au respectif SQL Join instructions. Le défaut type de jointure est un InnerJoin.

  • InnerJoin-Object (alias InnerJoin)
    Retourne les enregistrements qui ont des valeurs correspondantes dans les deux tables.

  • LeftJoin-Object (alias LeftJoin)
    Renvoie tous les enregistrements de la table de gauche et les enregistrements correspondants de la table de droite.

  • RightJoin-Object (alias RightJoin)
    Renvoie tous les enregistrements de la table de droite et les enregistrements correspondants de la table de droite.

  • FullJoin-Object (alias FullJoin)
    Renvoie tous les enregistrements lorsqu'il y a une correspondance dans la table gauche ou droite.

Remarques

  1. Tout Join les commandes sont compatibles avec PowerShell version 2 et supérieure.

Paramètres

-LeftTable <Object[]> et -RightTable <Object[]>

le -LeftTable et RightTable les paramètres définissent les tables gauche et droite à joindre. Il existe trois syntaxes possibles pour fournir les tables:

  • Utilisation du pipeline PowerShell: <LeftTable> | Join <RightTable>

  • Fournir les deux tables dans un tableau (séparés par une virgule) au premier argument: Join <LeftTable>,<RightTable>

  • Fournir les deux tables avec des arguments nommés: Join -Left <LeftTable> -Right <RightTable>

Remarques

  1. Si une seule table est fournie (Join <Table>), une auto auto-rejoindre sera effectué sur la table.

-On <String>|<Array>|<ScriptBlock> et -Equals <String>

le -On (alias Using) définit la condition qui spécifie comment joindre les tables et quelles lignes inclure dans le jeu de résultats (interne). le -On paramètre supporte les formats suivants:

  • String -Equals <String> Si la -On la valeur est un String et le -Equals <String> paramètres est fourni, la propriété dans la colonne de gauche définie par le -On valeur doit être égale à la propriété dans la colonne de droite définie par le -equals valeur à inclure dans le jeu de résultats (interne).

  • String ou Array Si la valeur est un String ou Array la -On le paramètre est similaire au SQL usingclause. Cela signifie que toutes les propriétés répertoriées doivent être égales (à gauche et à droite) pour être incluses dans le jeu de résultats (interne). Les propriétés répertoriées afficheront une valeur unique par défaut (voir aussi -Expressions).

  • ScriptBlock Toute expression conditionnelle où $Left définit la rangée gauche, $Right définit la ligne droite.

Remarques

  1. le ScriptBlock Le type a le plus de possibilités de comparaison, mais il est beaucoup plus lent que les autres types.

  2. Si la -On paramètre est omis ou d'un type inconnu, un rejoindre sera réalisée.

-Merge <HashTable>|<ScriptBlock>

Définit la manière dont les colonnes spécifiques portant le même nom doivent être fusionnées. le -Merge paramètre accepte les types: a HashTable  contenant l'expression de fusion spécifique pour chaque colonne ou ScriptBlock contenant l'expression de fusion par défaut pour toutes les colonnes pour lesquelles aucune expression de fusion n'est définie.
Où dans l'expression:

  • $_ contient chaque nom de colonne.
  • $Left tient la rangée gauche et $Right tient la bonne rangée.
  • $Left.$_ tient chaque valeur de gauche et $Right.$_ détient chaque valeur correcte.
  • $LeftIndex contient l'index de la ligne gauche actuelle et $RightIndex contient l'index de ligne droite actuel.

Remarques:

  1. Les expressions ne sont exécutées que si elles ont toutes deux une valeur (Left.$_) et la bonne valeur (Left.$_) existent (y compris les valeurs qui sont $Null) sinon la valeur existante est renvoyée.

  2. Si aucune expression n'est définie pour une colonne, l'expression {$Left.$_, $Right.$_} est utilisé. Cela signifie que les deux valeurs sont affectées (dans un tableau) à la propriété en cours.

  3. L’expression des colonnes définies par le -On <String>, -Equals <String>et sur <Array> est: {$Left.$_}  et ne peuvent être remplacées que par une expression spécifique à une colonne définie dans une table de hachage. Cela signifie qu'une valeur unique (soit $Left ou $Right qui n'est pas égal à $Null) est affecté à la propriété en cours.

  4. Pour utiliser des expressions spécifiques à une colonne et définir une expression par défaut utiliser un nom de clé de longueur zéro pour l'expression par défaut, par ex. -Merge @{"" = {$Left.$_}; "Column Name" = {$Right.$_}}

Exemples

Compte tenu des tableaux suivants:

   $ Employé $ département
+---------+---------+-------------+    +-------------+---------+---------+
|  Name   | Country | Department  |    |    Name     | Country | Manager |
+---------+---------+-------------+    +-------------+---------+---------+
| Aerts   | Belgium | Sales       |    | Engineering | Germany | Meyer   |
| Bauer   | Germany | Engineering |    | Marketing   | England | Morris  |
| Cook    | England | Sales       |    | Sales       | France  | Millet  |
| Duval   | France  | Engineering |    +-------------+---------+---------+
| Evans   | England | Marketing   |
| Fischer | Germany | Engineering |
+---------+---------+-------------+
PS C:\> # InnerJoin on Department = Name
PS C:\> $Employee | InnerJoin $Department Department -eq Name | Format-Table

Department  Name    Manager Country
----------  ----    ------- -------
Sales       Aerts   Millet  {Belgium, France}
Engineering Bauer   Meyer   {Germany, Germany}
Sales       Cook    Millet  {England, France}
Engineering Duval   Meyer   {France, Germany}
Marketing   Evans   Morris  {England, England}
Engineering Fischer Meyer   {Germany, Germany}


PS C:\> # LeftJoin using country (selecting Department.Name and Department.Country)
PS C:\> $Employee | LeftJoin ($Department | Select Manager,Country) Country | Format-Table

Department  Name    Manager Country
----------  ----    ------- -------
Engineering Bauer   Meyer   Germany
Sales       Cook    Morris  England
Engineering Duval   Millet  France
Marketing   Evans   Morris  England
Engineering Fischer Meyer   Germany
Sales       Aerts           Belgium


PS C:\> # InnerJoin on Employee.Department = Department.Name and Employee.Country = Department.Country (returning only the left name and - country)
PS C:\> $Employee | InnerJoin $Department {$Left.Department -eq $Right.Name -and $Left.Country -eq $Right.Country} {$Left.$_}

Department  Name    Manager Country
----------  ----    ------- -------
Engineering Bauer   Meyer   Germany
Marketing   Evans   Morris  England
Engineering Fischer Meyer   Germany


PS C:\> # Cross Join
PS C:\> $Employee | InnerJoin $Department | Format-Table

Department  Name                   Manager Country
----------  ----                   ------- -------
Sales       {Aerts, Engineering}   Meyer   {Belgium, Germany}
Sales       {Aerts, Marketing}     Morris  {Belgium, England}
Sales       {Aerts, Sales}         Millet  {Belgium, France}
Engineering {Bauer, Engineering}   Meyer   {Germany, Germany}
Engineering {Bauer, Marketing}     Morris  {Germany, England}
Engineering {Bauer, Sales}         Millet  {Germany, France}
Sales       {Cook, Engineering}    Meyer   {England, Germany}
Sales       {Cook, Marketing}      Morris  {England, England}
Sales       {Cook, Sales}          Millet  {England, France}
Engineering {Duval, Engineering}   Meyer   {France, Germany}
Engineering {Duval, Marketing}     Morris  {France, England}
Engineering {Duval, Sales}         Millet  {France, France}
Marketing   {Evans, Engineering}   Meyer   {England, Germany}
Marketing   {Evans, Marketing}     Morris  {England, England}
Marketing   {Evans, Sales}         Millet  {England, France}
Engineering {Fischer, Engineering} Meyer   {Germany, Germany}
Engineering {Fischer, Marketing}   Morris  {Germany, England}
Engineering {Fischer, Sales}       Millet  {Germany, France}

Mettre à jour la liste des services (remplacer les services existants par leur nom et en ajouter de nouveaux)

Import-CSV .\Svc.csv | LeftJoin (Get-Service) Name {$Right.$_} | Export-CSV .\Svc.csv

Mettre à jour la liste des processus et insérer uniquement des processus avec un processeur supérieur

Import-CSV .\CPU.csv | LeftJoin (Get-Process) ID {If ($Left.CPU -gt $Right.CPU) {$Left.$_} Else {$Right.$_}} | Export-CSV .\CPU.csv

Pour la dernière Join-Object version, voir le Galerie PowerShell ou le site du projet à: https://github.com/iRon7/Join-Object


10
2017-08-03 11:39