在Powershell中,将两个表合并为一个表的最佳方法是什么?

时间:2009-12-04 18:31:53

标签: scripting powershell dhcp

我对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

有没有更好的方法呢?

5 个答案:

答案 0 :(得分:14)

1。5年后,我在原始答案中粘贴的cmdlet经历了如此多的更新,以至于它已经完全过时了。因此,我已将codeReadMe替换为最新版本的链接。

Join-Object

可以使用以下命令从PowerShell Gallery下载Join-Object:

Install-Script -Name Join

Join 包中包含Join-Object(别名Join)命令和以下代理命令:

  • InnerJoin-Object,别名InnerJoinJoin-Object -JoinType Inner
    仅返回已连接的对象
  • LeftJoin-Object,别名LeftJoinJoin-Object -JoinType Left
    返回连接的对象和其余的左对象
  • RightJoin-Object,别名RightJoinJoin-Object -JoinType Right
    返回连接的对象和其他正确的对象
  • FullJoin-Object,别名FullJoinJoin-Object -JoinType Full
    返回连接的对象以及左右对象的其余部分
  • CrossJoin-Object,别名CrossJoinJoin-Object -JoinType Cross
    将每个左对象连接到每个右对象
  • Update-Object,别名UpdateJoin-Object -JoinType Left -Merge = {RightOrLeft.$_}
    使用正确的对象属性更新左对象
  • Merge-Object,别名MergeJoin-Object -JoinType Full -Merge = RightOrLeft.$_}
    使用正确的对象属性和插入更新左对象 如果相关财产的价值不相等,则正确。

ReadMe

完整的自述文件(和源代码)可从GitHub获得:https://github.com/iRon7/Join-Object

安装

下载(Install-Script -Name Join)后,dot sourcing可以简单地调用脚本:

. .\Join.ps1

您还可以考虑通过将脚本重命名为PowerShell模块( .psm1 )并将其移动到{中定义的模块文件夹之一 - 来将脚本转换为PowerShell模块。 {1}}。有关详细信息,请参阅:How to Write a PowerShell Script Module 注意:加载代理命令需要$env:PSModulePath命令。

答案

回答问题中的实际例子:

Import-Module

实施例

更多示例可以在相关的Stackoverflow问题中找到:

Join-Object test script

答案 1 :(得分:9)

Lee Holmes写了一个blog post on a Join-Object function来做你想做的事。太糟糕了,它还没有内置到PowerShell中。

答案 2 :(得分:1)

这也可以使用我的模块 Join-Object

Install-Module 'Join-Object'

Join-Object -Left $leases -Right $reservations -LeftJoinProperty 'IP' -RightJoinProperty 'IP'

关于性能,我对 10 万行的样本数据进行了测试:

  1. @js2010 发布的哈希表示例在 8 秒内运行。
  2. Join-Object 由我在 14 秒内跑完。
  3. LeftJoin by @iRon 在 1 分 50 秒内运行

答案 3 :(得分:0)

您可以像这样使用脚本块

$leases | select IP, NAME, @{N='MAC';E={$tmp=$_.IP;($reservations| ? IP -eq $tmp).MAC}}

答案 4 :(得分:0)

这是一个使用哈希表的简单示例。使用大数组,这会更快。

$leases =
'IP,Name
192.168.1.1,Apple
192.168.1.2,Pear
192.168.1.3,Banana
192.168.1.99,FishyPC' | convertfrom-csv

$reservations =
'IP,MAC
192.168.1.1,001D606839C2
192.168.1.2,00E018782BE1
192.168.1.3,0022192AF09C
192.168.1.4,0013D4352A0D' | convertfrom-csv

$hashRes=@{}
foreach ($resRecord in $reservations) {
  $hashRes[$resRecord.IP] = $resRecord
}

$leases | foreach {
  $other = $hashRes[$_.IP]

  [pscustomobject]@{IP=$_.IP
                   MAC=$other.MAC
                  Name=$_.name}
}
IP           MAC          Name
--           ---          ----
192.168.1.1  001D606839C2 Apple
192.168.1.2  00E018782BE1 Pear
192.168.1.3  0022192AF09C Banana
192.168.1.99              FishyPC