在 PowerShell 中对来自 CSV 的对象进行分组和 select

Group and select objects from CSV in PowerShell

我有一份用户、他们的设备和他们的管理员的列表。 manager 和 user 可以重复,但 deviceID 是唯一的。我如何获得一份清单,以便我可以向每位经理发送一封电子邮件,让他们知道他们的员工使用了多少个单元以及使用哪个单元?我只对拥有 2 个或更多设备的人感兴趣。

想要的输出是这样的(如果有人想给我更好的输出建议,我洗耳恭听)。

Manager  deviceID
M1        U1=D1 D2, U3=D4 D5

我的代码现在的样子:

$csv = @"
manager,user,deviceID
M1,U1,D1
M1,U1,D2
M2,U2,D3
M1,U3,D4
M1,U3,D5
"@ -split "`r`n" | ConvertFrom-Csv

$csv | Group-Object -Property Manager |
     Select-Object @{N='Manager';E={($_.Group[0]).Manager}}, 
@{N="User";E={($_.group).user}}, 
@{N="deviceID";E={ foreach($row in $_.Group){ $row.user + ' = ' + $row.deviceID}}} 

这是一个哈希表方法:

$managerGroups = $csv | Group-Object -Property manager -AsHashTable

foreach ($item in $managerGroups.GetEnumerator()) {
    $userGroups = $item.Value | Group-Object -Property user -AsHashTable

    & {
        [PSCustomObject]@{
            Manager = $item.Key
            DeviceId = & {
                foreach ($user in $userGroups.GetEnumerator()) {
                    [PSCustomObject]@{
                        User = $user.Key
                        Devices = & {
                            foreach ($device in $user.Value) {
                                $device.deviceID
                            }
                        }
                    }
                }
            }
        }
    } | Select-Object -Property Manager, @{
        Name='DeviceId';
        Expression={
            & {
                foreach ($deviceId in $_.DeviceId) {
                    "$($deviceId.User) = $($deviceId.Devices -join " ")"
                }
            } | Join-String -Separator ", "
        }
    }
}

输出:

Manager DeviceId
------- --------
M1      U1 = D1 D2, U3 = D4 D5
M2      U2 = D3

解释:

您也可以使用完整的管道方法:

$managerGroups = $csv | Group-Object -Property manager -AsHashTable

$managerGroups.GetEnumerator() | Foreach-Object {
    $manager = $_.Key

    $userGroups = $_.Value | Group-Object -Property user -AsHashTable

    [PSCustomObject]@{
        Manager = $manager
        DeviceId = $userGroups.GetEnumerator() | ForEach-Object {
            [PSCustomObject]@{
                User = $_.Key
                Devices = $_.Value | ForEach-Object {$_.deviceId}
            }
        }
    } | Select-Object -Property Manager, @{
        Name='DeviceId';
        Expression={
            $_.DeviceId | ForEach-Object { 
                "$($_.User) = $($_.Devices -join " ")"
            } | Join-String -Separator ', '
        }
    }
}

这可能会更慢,因为在使用 .NET 类型或 [PSCustomObject] 时,foreach 成员枚举比 Foreach-Object pipelines. You can have a look at this answer 要快得多以获取更多信息。

既然你说你只对列出使用多个设备的用户感兴趣,也许这对你有帮助:

$csv = @"
manager,user,deviceID
M1,U1,D1
M1,U1,D2
M2,U2,D3
M1,U3,D4
M1,U3,D5
"@ -split "`r`n" | ConvertFrom-Csv

# first group on Manager
$result = $csv | Group-Object -Property Manager | ForEach-Object {
    $manager = $_.Name
    # next, group the groups on User and select only where a user is mentioned twice or more times
    $_.Group | Group-Object User | Where-Object { $_.Count -gt 1 } | ForEach-Object {
        [PsCustomObject]@{
            Manager = $manager
            User = $_.Name
            Devices = $_.Group.DeviceID -join ' '
        }
    }
}

# output on screen
$result

# output to CSV
$result | Export-Csv -Path 'managerReport.csv' -NoTypeInformation

输出:

Manager User Devices
------- ---- -------
M1      U1   D1 D2  
M1      U3   D4 D5
# to separate the results so each manager gets his/her personal report:
$result | Group-Object Manager | ForEach-Object {
    # send an email to the manager. For demo just output to console
    Write-Host "Send mail to manager $($_.Name):" -ForegroundColor Yellow
    $_.Group | Format-Table -AutoSize | Out-String
}