[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[问题求助] 使用powershell汇总excel表中的单元格数据

本帖最后由 5i365 于 2022-9-17 19:59 编辑

当前文件夹下有N多个xlsx文件, 只处理每个文件中第1个工作薄中的第1个工作表, 表的内容很简单,示例如下:
_____________________________________________________A.xlsx
姓名, 语文, 数学, 社会, 历史
张三, 35, 39, 88, 76

_____________________________________________________B.xlsx
姓名, 语文, 数学, 社会, 历史
李四, 36, 39, 89, 78

_____________________________________________________C.xlsx
姓名, 语文, 数学, 社会, 历史
张三, 45, 31, 72, 84





相同文件夹下,还有很多相同格式的文件...
__________________________________________________________________________


我想查询张三这个人的: 语文, 数学, 社会, 历史 成绩的总和, 实际上就是计算所有 姓名为 张三的 工作表的 B2  C2  D2  E2的和


但我不知道张三在哪几个xlsx文件的表中


上面的示例中, A.xlsx 和 C.xlsx 文件中有张三, 则最后的处理结果: 输出对应的两个表中 B2  C2  D2  E2的和, 即:


姓名, 语文, 数学, 社会, 历史
张三, 80, 70, 160, 160

求大佬帮忙, 多谢
本人所发所有贴子或代码, 诸大侠若认为有改进之处,请不吝赐教,感激不尽!

比较一下
  1. #@&echo "ok"
  2. #&echo "ok"
复制代码

TOP

回复 34# wanghan519


不是不是当不起
也是借鉴前辈们的
还真不知道有没得啥子影响
1

评分人数

TOP

回复 2# idwma


    大师,我在很多地方抄袭你这回答的第一句,非常好用
  1. #@&cls&powershell "type '%~0'|out-string|iex"&pause&exit
复制代码
请问,第二个字符,那个@在这里起什么作用,删掉似乎也能运行,只是不知道有什么影响,多谢解惑

TOP

本帖最后由 5i365 于 2022-9-20 19:28 编辑

回复 32# flashercs

多谢大侠
本人所发所有贴子或代码, 诸大侠若认为有改进之处,请不吝赐教,感激不尽!

TOP

本帖最后由 flashercs 于 2022-9-20 19:00 编辑

出错是因为 有的.xlsx不是真正Excel文件,披着羊皮的狼而已.
  1. Add-Type -LiteralPath .\EPPlus.dll -ErrorAction Stop
  2. $fields = @('姓名:', '语文:', '数学:', '社会:', '历史:')
  3. $keyField = '姓名:'
  4. $groupPso = Get-ChildItem -Path .\*.xlsx -Filter *.xlsx | Where-Object { -not $_.PSIsContainer } | ForEach-Object {
  5.   try {
  6.     $_ | Resolve-Path -Relative | Write-Host
  7.     $pack = New-Object OfficeOpenXml.ExcelPackage -ArgumentList $_.FullName -ErrorAction Stop
  8.     $pso = New-Object psobject
  9.     $a2d = $pack.Workbook.Worksheets[1].Cells.Value
  10.     for ($x = $a2d.GetLowerBound(0); $x -le $a2d.GetUpperBound(0); $x++) {
  11.       $propName = $null
  12.       for ($y = $a2d.GetLowerBound(1); $y -le $a2d.GetUpperBound(1); $y++) {
  13.         if ($null -eq $propName) {
  14.           if ($fields -contains $a2d[$x, $y]) {
  15.             $propName = $a2d[$x, $y]
  16.           }
  17.         } else {
  18.           if ($null -ne $a2d[$x, $y]) {
  19.             $pso | Add-Member -MemberType NoteProperty -Name $propName -Value $a2d[$x, $y]
  20.             $propName = $null
  21.           }
  22.         }
  23.       }
  24.     }
  25.     $pso
  26.   } finally {
  27.     if ($pack) {
  28.       $pack.Dispose()
  29.       $pack = $null
  30.     }
  31.   }
  32.   trap { }
  33. } | Group-Object -Property $keyField
  34. function Get-StudentScore {
  35.   param (
  36.     [string[]]$UserName
  37.   )
  38.   $groupPso | Where-Object { $null -eq $UserName -or $UserName -contains '*' -or $UserName -contains $_.Name } | ForEach-Object {
  39.     $pso = New-Object psobject -Property @{$keyField = $_.Name }
  40.     $_.Group | Measure-Object -Property ($fields -ne $keyField) -Sum | ForEach-Object {
  41.       $pso | Add-Member -MemberType NoteProperty -Name $_.Property -Value $_.Sum.ToString('f2')
  42.     }
  43.     $pso
  44.   }
  45. }
  46. # main
  47. # search 佟玉
  48. # Get-StudentScore -UserName 佟玉 | Format-Table -AutoSize
  49. # search 张三,李四
  50. # Get-StudentScore -UserName 张三, 李四 | Format-Table -AutoSize
  51. # search 所有学生
  52. # Get-StudentScore -UserName * | Format-Table -AutoSize
  53. # search 所有学生
  54. # Get-StudentScore | Format-Table -AutoSize
  55. # 左对齐
  56. # Get-StudentScore | Out-GridView -Title 学生成绩汇总 -Wait
  57. # 筛选姓名
  58. # Get-StudentScore | Out-GridView -Title 学生成绩汇总_多选 -OutputMode Multiple | Out-GridView -Title 学生成绩汇总_已选择 -Wait
  59. Add-Type -AssemblyName System.Windows.Forms
  60. Add-Type -AssemblyName System.Drawing
  61. $form = New-Object System.Windows.Forms.Form
  62. $form.Text = '双击要查询的姓名'
  63. $Form.FormBorderStyle = "FixedToolWindow"
  64. $form.StartPosition = 'CenterScreen'
  65. $form.Font = New-Object System.Drawing.Font("微软雅黑", 10, [Drawing.FontStyle]::Bold)
  66. $form.ClientSize = '160, 300'
  67. $listBox = New-Object System.Windows.Forms.Listbox
  68. # $listBox.Dock = 'Fill'
  69. $listBox.Location = '0, 0'
  70. $listBox.Size = '160,280'
  71. $listBox.Anchor = 'Left,Top,Right,Bottom'
  72. $listBox.SelectionMode = 'MultiExtended'
  73. $listBox.DataSource = [System.Collections.ArrayList]@($groupPso.Name | Sort-Object)
  74. $form.Controls.Add($listBox)
  75. $OKButton = New-Object System.Windows.Forms.Button
  76. $OKButton.Location = '0,275'
  77. $OKButton.Size = '160,25'
  78. $OKButton.Text = 'OK'
  79. $OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
  80. $OKButton.Anchor = 'Bottom'
  81. $form.AcceptButton = $OKButton
  82. $form.Controls.Add($OKButton)
  83. $form.TopMost = $true
  84. if ($groupPso.Count -gt 10) {
  85.   $form.ClientSize = '160,700'
  86. }
  87. $result = $form.ShowDialog()
  88. if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
  89.   $selectedItems = $listBox.SelectedItems
  90. }
  91. ($form, $OKButton, $listBox).Dispose()
  92. if (-not $selectedItems) {
  93.   exit
  94. }
  95. $form = New-Object System.Windows.Forms.Form
  96. $form.Text = '显示结果'
  97. $form.ClientSize = '200, 300'
  98. $Form.FormBorderStyle = "FixedToolWindow"
  99. $form.StartPosition = 'CenterScreen'
  100. $textbox1 = New-Object 'System.Windows.Forms.TextBox'
  101. $textbox1.Name = 'textbox1'
  102. $textbox1.Dock = 'Fill'
  103. $textbox1.Multiline = $True
  104. $textbox1.ScrollBars = 'Both'
  105. $textbox1.Font = New-Object System.Drawing.Font("微软雅黑", 10)
  106. $form.Controls.Add($textbox1)
  107. $textbox1.AppendText((Get-StudentScore -UserName $selectedItems | Format-List | Out-String -Width ([int]::MaxValue)))
  108. $result = $form.ShowDialog()
  109. ($form, $textbox1).Dispose()
复制代码
微信:flashercs
QQ:49908356

TOP

回复 29# 5i365

发现一个问题, 经常有下面的错误提示, 但是也能显示结果,
不知道是不是获取数据时出错了, 这个挺重要, 要是数据错了, 成绩汇总肯定也错了, 学生就哭晕了

ERROR: New-Object : Exception calling ".ctor" with "1" argument(s): "The file is not an valid Package file. If the file is encrypted, please supply the password in th
ERROR: e constructor."
EP3.ps1 (7, 11): ERROR: At Line: 7 char: 11
ERROR: + ...     $pack = New-Object OfficeOpenXml.ExcelPackage -ArgumentList $_.Fu ...
ERROR: +                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ERROR:     + CategoryInfo          : InvalidOperation: ( [New-Object], MethodInvocationException
ERROR:     + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
ERROR:
ERROR: Cannot index into a null array.
EP3.ps1 (9, 3): ERROR: At Line: 9 char: 3
ERROR: +         $a2d = $pack.Workbook.Worksheets[1].Cells.Value
ERROR: +         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ERROR:     + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
ERROR:     + FullyQualifiedErrorId : NullArray
本人所发所有贴子或代码, 诸大侠若认为有改进之处,请不吝赐教,感激不尽!

TOP

本帖最后由 5i365 于 2022-9-20 09:47 编辑

回复 28# flashercs


关于结果显示那个, 感觉太复杂了, 我不需要过滤, 搜索之类的花哨功能
我想了一个简洁实用的方法:
还是用上楼的form方法
它里面仅有一个多行编辑框控件, 把结果按 Format-list 格式显示在里面就可以了    下面是能用的代码

  1. Add-Type -AssemblyName System.Windows.Forms
  2. $form = New-Object System.Windows.Forms.Form
  3. $form.Text = '显示结果'
  4. $form.ClientSize = '200, 300'
  5. $Form.FormBorderStyle = "FixedToolWindow"
  6. $form.StartPosition = 'CenterScreen'
  7. $textbox1 = New-Object 'System.Windows.Forms.TextBox'
  8. $textbox1.Name = 'textbox1'
  9. $textbox1.Dock = 'Fill'
  10. $textbox1.Multiline = $True
  11. $textbox1.Font = New-Object drawing.Font("微软雅黑", 10)
  12. $form.Controls.Add($textbox1)
  13. $result = $form.ShowDialog()
复制代码
本人所发所有贴子或代码, 诸大侠若认为有改进之处,请不吝赐教,感激不尽!

TOP

本帖最后由 5i365 于 2022-9-20 09:49 编辑

回复 28# flashercs

多谢大侠, 刚看到,

关于最开始的列表框, 我找到了我说的那种效果, 就是设置一下列表框的属性 $listBox.Dock = 'Fill'
但是我想把OK按钮放在最下面, 宽度和对话框等宽,

另外: Form高度能否设置最大高度? 即:默认是300, 当姓名多时,则自动变为最大高度800?, 以前看到过这种效果, 如下图所示
另外, 如何把姓名按姓的第一个拼音字母按a-z排序?




  1. Add-Type -AssemblyName System.Windows.Forms
  2. $form = New-Object System.Windows.Forms.Form
  3. $form.Text = '双击要查询的姓名'
  4. $Form.FormBorderStyle = "FixedToolWindow"
  5. $form.StartPosition = 'CenterScreen'
  6. $form.ClientSize = '160, 300'
  7. $listBox = New-Object System.Windows.Forms.Listbox
  8. $listBox.Dock = 'Fill'
  9. $listBox.SelectionMode = 'MultiExtended'
  10. $listBox.Font = New-Object drawing.Font("微软雅黑", 10, [Drawing.FontStyle]::Bold)
  11. [void]$listBox.Items.Add('张三')
  12. [void]$listBox.Items.Add('李四')
  13. [void]$listBox.Items.Add('王五')
  14. [void]$listBox.Items.Add('赵六')
  15. $form.Controls.Add($listBox)
  16. $form.Topmost = $true
  17. $result = $form.ShowDialog()
  18. if ($result -eq [System.Windows.Forms.DialogResult]::OK)
  19. {
  20.         $x = $listBox.SelectedItems
  21.         $x
  22. }
复制代码
本人所发所有贴子或代码, 诸大侠若认为有改进之处,请不吝赐教,感激不尽!

TOP

本帖最后由 flashercs 于 2022-9-19 21:08 编辑

回复 26# 5i365

winform选择
  1. Add-Type -LiteralPath .\EPPlus.dll -ErrorAction Stop
  2. $fields = @('姓名:', '语文:', '数学:', '社会:', '历史:')
  3. $keyField = '姓名:'
  4. $groupPso = Get-ChildItem -Path .\*.xlsx -Filter *.xlsx | Where-Object { -not $_.PSIsContainer } | ForEach-Object {
  5.   try {
  6.     $pack = New-Object OfficeOpenXml.ExcelPackage -ArgumentList $_.FullName
  7.     $pso = New-Object psobject
  8.     $a2d = $pack.Workbook.Worksheets[1].Cells.Value
  9.     for ($x = $a2d.GetLowerBound(0); $x -le $a2d.GetUpperBound(0); $x++) {
  10.       $propName = $null
  11.       for ($y = $a2d.GetLowerBound(1); $y -le $a2d.GetUpperBound(1); $y++) {
  12.         if ($null -eq $propName) {
  13.           if ($fields -contains $a2d[$x, $y]) {
  14.             $propName = $a2d[$x, $y]
  15.           }
  16.         } else {
  17.           if ($null -ne $a2d[$x, $y]) {
  18.             $pso | Add-Member -MemberType NoteProperty -Name $propName -Value $a2d[$x, $y]
  19.             $propName = $null
  20.           }
  21.         }
  22.       }
  23.     }
  24.     $pso
  25.   } finally {
  26.     if ($pack) {
  27.       $pack.Dispose()
  28.       $pack = $null
  29.     }
  30.   }
  31.   trap {}
  32. } | Group-Object -Property $keyField
  33. function Get-StudentScore {
  34.   param (
  35.     [string[]]$UserName
  36.   )
  37.   $groupPso | Where-Object { $null -eq $UserName -or $UserName -contains '*' -or $UserName -contains $_.Name } | ForEach-Object {
  38.     $pso = New-Object psobject -Property @{$keyField = $_.Name }
  39.     $_.Group | Measure-Object -Property ($fields -ne $keyField) -Sum | ForEach-Object {
  40.       $pso | Add-Member -MemberType NoteProperty -Name $_.Property -Value ([int]$_.Sum)
  41.     }
  42.     $pso
  43.   }
  44. }
  45. # main
  46. # search 佟玉
  47. # Get-StudentScore -UserName 佟玉 | Format-Table -AutoSize
  48. # search 张三,李四
  49. # Get-StudentScore -UserName 张三, 李四 | Format-Table -AutoSize
  50. # search 所有学生
  51. # Get-StudentScore -UserName * | Format-Table -AutoSize
  52. # search 所有学生
  53. # Get-StudentScore | Format-Table -AutoSize
  54. # 左对齐
  55. # Get-StudentScore | Out-GridView -Title 学生成绩汇总 -Wait
  56. # 筛选姓名
  57. # Get-StudentScore | Out-GridView -Title 学生成绩汇总_多选 -OutputMode Multiple | Out-GridView -Title 学生成绩汇总_已选择 -Wait
  58. Add-Type -AssemblyName System.Windows.Forms
  59. Add-Type -AssemblyName System.Drawing
  60. $form = New-Object System.Windows.Forms.Form
  61. $form.Text = '选择列表'
  62. $form.Size = New-Object System.Drawing.Size(300, 200)
  63. $form.StartPosition = 'CenterScreen'
  64. $OKButton = New-Object System.Windows.Forms.Button
  65. $OKButton.Location = New-Object System.Drawing.Point(75, 120)
  66. $OKButton.Size = New-Object System.Drawing.Size(75, 23)
  67. $OKButton.Text = 'OK'
  68. $OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
  69. $form.AcceptButton = $OKButton
  70. $form.Controls.Add($OKButton)
  71. $CancelButton = New-Object System.Windows.Forms.Button
  72. $CancelButton.Location = New-Object System.Drawing.Point(150, 120)
  73. $CancelButton.Size = New-Object System.Drawing.Size(75, 23)
  74. $CancelButton.Text = 'Cancel'
  75. $CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
  76. $form.CancelButton = $CancelButton
  77. $form.Controls.Add($CancelButton)
  78. $label = New-Object System.Windows.Forms.Label
  79. $label.Location = New-Object System.Drawing.Point(10, 20)
  80. $label.Size = New-Object System.Drawing.Size(280, 20)
  81. $label.Text = '选择你要查询的学生的姓名:'
  82. $form.Controls.Add($label)
  83. $listBox = New-Object System.Windows.Forms.Listbox
  84. $listBox.Location = New-Object System.Drawing.Point(10, 40)
  85. $listBox.Size = New-Object System.Drawing.Size(260, 20)
  86. $listBox.SelectionMode = 'MultiExtended'
  87. $listBox.DataSource = [System.Collections.ArrayList]@($groupPso.Name)
  88. $listBox.Height = 70
  89. $form.Controls.Add($listBox)
  90. $form.Topmost = $true
  91. $result = $form.ShowDialog()
  92. if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
  93.   $x = $listBox.SelectedItems
  94.   $x
  95. }
  96. Get-StudentScore -UserName $x | Out-GridView -Title 学生成绩汇总 -Wait
  97. ($form, $OKButton, $CancelButton, $label, $listBox).Dispose()
复制代码
微信:flashercs
QQ:49908356

TOP

回复 23# 5i365


利用powershell_ise的 WPF GUI组件 GridView来选择对象,比winform选择要方便得多.可以多选,按Ctrl或Shift进行多选.
16楼又修改了一下.
微信:flashercs
QQ:49908356

TOP

本帖最后由 5i365 于 2022-9-19 19:56 编辑

回复 25# flashercs


我使用的那个软件能把ps生成exe, 所以我想
用  列表框 显示这一堆xlsx文件中,所包含的所有  姓名,


用  消息框   显示对齐的结果


执行ps1文件操作就相对麻烦了

生成exe 我已经试了, 可以成功, 就是不太完美, 存在上面所提到的问题
本人所发所有贴子或代码, 诸大侠若认为有改进之处,请不吝赐教,感激不尽!

TOP

本帖最后由 flashercs 于 2022-9-19 19:31 编辑

回复 24# 5i365
  1. # 左对齐
  2. Get-StudentScore | Out-GridView -Title 学生成绩汇总 -Wait
复制代码
可以在GridView中进行筛选姓名,也可以筛选成绩.


微信:flashercs
QQ:49908356

TOP

本帖最后由 5i365 于 2022-9-19 14:09 编辑

回复 16# flashercs

怎样让输出的结果, 上下的内容左对齐? 现在输出后, 属性名和属性值上下没有对齐, 看分数不太明确
在消息框中显示时对齐就好多了
有什么办法用带表格线的形式显示在消息框中?

[System.Windows.Forms.MessageBox]::Show("输出的多行对齐的结果", "标题")
本人所发所有贴子或代码, 诸大侠若认为有改进之处,请不吝赐教,感激不尽!

TOP

本帖最后由 5i365 于 2022-9-19 13:44 编辑

回复 21# flashercs


试了几个, 感觉应该可以了,
请问, 怎样在上面的代码中把所有学生姓名的存到数组里? 然后填充到下面的列表框中? 这样操作方便一些
即: 执行上面代码时, 先显示这个列表框, 我从里面选择某个人的姓名, 然后确定, 就出现了该人的汇总成绩

下面的代码有点臃肿, 我也以前看到过类似列表框的代码, 没有使用System.Drawing , 才只有几行代码, 刚搜索了一下, 没找到

另外还有一点, 如果列表中的项比较多, 窗口要相应的添加高度

  1. Add-Type -AssemblyName System.Windows.Forms
  2. Add-Type -AssemblyName System.Drawing
  3. $form = New-Object System.Windows.Forms.Form
  4. $form.Text = '选择列表'
  5. $form.Size = New-Object System.Drawing.Size(300, 200)
  6. $form.StartPosition = 'CenterScreen'
  7. $OKButton = New-Object System.Windows.Forms.Button
  8. $OKButton.Location = New-Object System.Drawing.Point(75, 120)
  9. $OKButton.Size = New-Object System.Drawing.Size(75, 23)
  10. $OKButton.Text = 'OK'
  11. $OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
  12. $form.AcceptButton = $OKButton
  13. $form.Controls.Add($OKButton)
  14. $CancelButton = New-Object System.Windows.Forms.Button
  15. $CancelButton.Location = New-Object System.Drawing.Point(150, 120)
  16. $CancelButton.Size = New-Object System.Drawing.Size(75, 23)
  17. $CancelButton.Text = 'Cancel'
  18. $CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
  19. $form.CancelButton = $CancelButton
  20. $form.Controls.Add($CancelButton)
  21. $label = New-Object System.Windows.Forms.Label
  22. $label.Location = New-Object System.Drawing.Point(10, 20)
  23. $label.Size = New-Object System.Drawing.Size(280, 20)
  24. $label.Text = '选择你要查询的学生的姓名:'
  25. $form.Controls.Add($label)
  26. $listBox = New-Object System.Windows.Forms.Listbox
  27. $listBox.Location = New-Object System.Drawing.Point(10, 40)
  28. $listBox.Size = New-Object System.Drawing.Size(260, 20)
  29. #$listBox.SelectionMode = 'MultiExtended'
  30. [void]$listBox.Items.Add('张三')
  31. [void]$listBox.Items.Add('李四')
  32. [void]$listBox.Items.Add('王五')
  33. [void]$listBox.Items.Add('赵六')
  34. $listBox.Height = 70
  35. $form.Controls.Add($listBox)
  36. $form.Topmost = $true
  37. $result = $form.ShowDialog()
  38. if ($result -eq [System.Windows.Forms.DialogResult]::OK)
  39. {
  40.         $x = $listBox.SelectedItems
  41.         $x
  42. }
复制代码
本人所发所有贴子或代码, 诸大侠若认为有改进之处,请不吝赐教,感激不尽!

TOP

返回列表