Powershell Group-Object - 使用多个对象进行过滤

时间:2017-10-07 02:41:24

标签: powershell

我有一个CSV设备缺少安全更新以及更新发布的日期和kb编号。

devicename,date,kb
Desktop1,9/12/17,KB4011055
Desktop1,9/12/17,KB4038866
Desktop2,9/12/17,KB4011055
Desktop2,6/13/17,KB3203467

我正在尝试编译缺少过去30天内发布的更新的设备列表,但排除了也缺少旧版更新的设备。所以在上面的例子中,我想要的唯一设备是Desktop 1。 我知道我可以做这样的事情来查看30天窗口以下的设备,但仍然包含其他条目超过30天的设备。

$AllDevices | Where-Object {[datetime]$_.date_released -gt ((get-date).adddays(-30))} 

我在想我可以使用Group-Object devicename将所有设备组合在一起,但我不确定如何从那里查看日期。 有什么想法吗?

2 个答案:

答案 0 :(得分:2)

假设$AllDevices被赋予了类似
的输出 Import-Csv c:\path\to\some.csv并且使用了PSv3 +。

$AllDevices | Group-Object devicename | Where-Object {
  -not ([datetime[]] $_.Group.date -le (Get-Date).AddDays(-30))
} | Select-Object @{ l='devicename'; e='Name' }, @{ l='kbs'; e={ $_.Group.kb } }

通过样本输入,可以得到:

devicename kbs                   
---------- ---                   
Desktop1   {KB4011055, KB4038866}

<强>解释

  • Group-Object devicename按设备名对所有输入对象进行分组,输出一组[Microsoft.PowerShell.Commands.GroupInfo]个实例,每个实例代表共享给定设备名称的所有输入对象(例如Desktop1) - 见Get-Help Group-Object

  • 然后使用Where-Object调用来清除包含日期超过30天的对象的组。

    • [datetime[]] $_.Group.date从组[datetime[]]的每个成员的日期时间字符串(.date)创建一个日期时间对象数组$_.Group。< / p>

      • 请注意,$_.Group是组成该组的输入对象的集合,即使.date直接应用于$_.Group.date也是-le (Get-Date).AddDays(-30)在每个集合成员上访问属性,并在数组中收集结果 - 这个方便的快捷语法称为member enumeration,并在PSv3中引入。
    • -le过滤该数组仅返回日期超过30天的成员;请注意,应用于数组值 LHS的-not会返回过滤的子数组,而不是布尔值。

    • -le否定了$False比较的结果,该结果强制将过滤后的数组解释为 Boolean ,如果布尔,则计算结果为$True数组为空,否则为-le;换句话说:如果一个或多个小组成员的日期超过30天,则$True比较将评估为-not作为布尔值,.Name否定。 这导致包含至少1个超过30天的日期的组(和其他设备)从进一步的管道处理中删除。

  • Select-Object然后只接收其成员都具有最近30天内日期的组对象,并使用calculated properties (via hashtable literals (@{...}) with standardized entries)构造输出对象:

    • 组对象的Group-Object属性包含传递给devicename的分组属性的值,在这种情况下是输入对象的@{ l='devicename'; e='Name' }属性; .Name只需将devicename媒体资源重命名为@{ l='kbs'; e={ $_.Group.kb } }

    • kbs然后构造一个kb属性,其中包含来自每个组成员的{ ... }值的数组,通过成员枚举检索脚本块Select-Object

    • 请注意,[pscustomobject]输出devicename个实例仅包含明确定义的属性;在这种情况下,kbsShowModal

答案 1 :(得分:1)

我建议其他解决方案:

import-csv "C:\temp\test.csv" | 
    select *, @{N="Date";E={[DateTime]$_.Date}} -ExcludeProperty "Date" |
               group devicename | 
                %{
                    if (($_.Group | where Date -le (Get-Date).AddDays(-30)).Count -eq 0)
                    {
                       $LastUpdate=$_.Group | sort Date, kb -Descending | select -First 1
                        [pscustomobject]@{
                        DeviceName=$LastUpdate.DeviceName
                        DateLastUpdate=$LastUpdate.Date
                        LastUpdate=$LastUpdate.Kb
                        UpdateList=$_.Group.Kb -join ', '
                        Group=$_.Group
                        } 
                    }

                }