В 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
)
Возвращает все записи, когда есть совпадение в левой или правой таблице.
Примечания
- все
Join
команды совместимы с версией PowerShell 2 и выше.
параметры
-LeftTable <Object[]>
и -RightTable <Object[]>
на -LeftTable
и RightTable
параметры определяют левую и правую таблицы для соединения. Существует три возможных синтаксиса для предоставления таблиц:
использование конвейера PowerShell:
<LeftTable> | Join <RightTable>
предоставление обеих таблиц в массиве (разделенном запятой) при первом аргументе позиция:
Join <LeftTable>,<RightTable>
предоставление обеих таблиц именованных аргументов:
Join -Left <LeftTable> -Right <RightTable>
Примечания
- если только одна таблица поставлена (
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