在 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
解释:
- 使用
-AsHashTable
开关将 Group-Object
and convert to a System.Collections.Hashtable
的经理分组。
- 用
System.Collections.HashTable.GetEnumerator()
迭代哈希表
- 也将
Group-Object
and convert to a System.Collections.Hashtable
的用户分组。
- 创建一个包含
Manager
和 DeviceId
列的 System.Management.Automation.PSCustomObject
。
- 创建用户设备分组的内部
System.Management.Automation.PSCustomObject
。
- 使用
Select-Object
到 select 最后的 Manager
列和 DeviceId
列,其中 DeviceId
列是 属性 的计算结果用户设备组。
您也可以使用完整的管道方法:
$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
}
我有一份用户、他们的设备和他们的管理员的列表。 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
解释:
- 使用
-AsHashTable
开关将Group-Object
and convert to aSystem.Collections.Hashtable
的经理分组。 - 用
System.Collections.HashTable.GetEnumerator()
迭代哈希表
- 也将
Group-Object
and convert to aSystem.Collections.Hashtable
的用户分组。 - 创建一个包含
Manager
和DeviceId
列的System.Management.Automation.PSCustomObject
。 - 创建用户设备分组的内部
System.Management.Automation.PSCustomObject
。 - 使用
Select-Object
到 select 最后的Manager
列和DeviceId
列,其中DeviceId
列是 属性 的计算结果用户设备组。
您也可以使用完整的管道方法:
$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
}