В Powershell, каков наилучший способ объединить две таблицы в одну?

Я довольно новичок в Powershell, и мне интересно, знает ли кто-нибудь лучший способ выполнить следующую проблему примера.

у меня есть массив сопоставлений от IP-адреса до имени хоста. Это представляет собой список активных аренды DHCP:

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

у меня есть другой массив сопоставлений от MAC-адреса до IP-адреса. Это представляет собой список оговорок 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

для удобства я смог создать третий массив сопоставлений с MAC адрес к IP-адресу и имени хоста, используя следующий код. Идея в том, что $reservations должно получить третье поле "Name", которое заполняется всякий раз, когда есть соответствующее поле" IP":

$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}}
    }
}

желаемый результат примерно такой:

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

есть ли лучший способ сделать это?

2 ответов


Ли Холмс написал сообщение в блоге о функции Join-Object что делает то, что вы хотите. Жаль, что он еще не встроен в PowerShell.


Join-Object

на Join-Object (псевдоним Join) функция объединяет столбцы из двух массивов объектов в новый массив объектов, который может быть сохранен как таблица (Export-CSV) или использовать как есть.

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"

синтаксис

<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>]

команды

на Join-Object (псевдоним Join) функция одна функция с несколькими псевдонимы, объединяющие две таблицы (каждая из которых состоит из массива PSCustomObjects) аналогично соответствующему SQL Join инструкция. Значение по умолчанию тип соединения это InnerJoin.

  • InnerJoin-Object (псевдоним InnerJoin)
    Возвращает записи, имеющие совпадающие значения в обеих таблицах.

  • LeftJoin-Object (псевдоним LeftJoin)
    Возвращает все записи из левой таблицы и сопоставлены записи из правой таблицы.

  • RightJoin-Object (псевдоним RightJoin)
    Возвращает все записи из правой таблицы, и совпадающие записи из правой таблицы.

  • FullJoin-Object (псевдоним FullJoin)
    Возвращает все записи, когда есть совпадение в левой или правой таблице.

Примечания

  1. все Join команды совместимы с версией PowerShell 2 и выше.

параметры

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

на -LeftTable и RightTable параметры определяют левую и правую таблицы для соединения. Существует три возможных синтаксиса для предоставления таблиц:

  • использование конвейера PowerShell: <LeftTable> | Join <RightTable>

  • предоставление обеих таблиц в массиве (разделенном запятой) при первом аргументе позиция: Join <LeftTable>,<RightTable>

  • предоставление обеих таблиц именованных аргументов: Join -Left <LeftTable> -Right <RightTable>

Примечания

  1. если только одна таблица поставлена (Join <Table>), С собственной self-join будет выполняться на столе.

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

на -On (псевдоним Using) параметр определяет условие, указывающее, как соединить таблицы и какие строки включить в (внутренний) результирующий набор. The это. Это означает, что оба значения назначаются (в массиве) текущему свойству.

  • выражение для столбцов, определенных -On <String>, -Equals <String>и <Array> is:{$Left.$_} и может быть отменено только определенным выражением столбца, определенным в хэш-таблице. Это означает, что одно значение (либо $Left или $Right что не равно $Null) присваивается текущему свойству.

  • To используйте выражения столбцаи определение выражения по умолчанию используйте имя ключа нулевой длины для выражения по умолчанию, например -Merge @{"" = {$Left.$_}; "Column Name" = {$Right.$_}}

  • примеры

    даны следующие таблицы:

       $Employee                               $Department
    +---------+---------+-------------+    +-------------+---------+---------+
    |  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}
    

    обновить список служб (заменить существующие службы на имя и добавить новые)

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

    обновить список процессов и только вставить процессы с более высоким CPU

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

    для последний Join-Object версия, см. Коллекции PowerShell или сайт проекта по адресу:https://github.com/iRon7/Join-Object