【问题标题】:Looping Through Files to Run PowerShell Script循环文件以运行 PowerShell 脚本
【发布时间】:2020-12-05 02:36:04
【问题描述】:

我正在尝试遍历文件夹中未知数量的 Excel 文件,并将每个文件中的第一个工作表重命名为特定名称。

到目前为止我所拥有的是:

Clear-Host
$file = Get-ChildItem -Path "C:\PowerShell\BA" -Name -Include *.xlsx
Write-Output $file

这确实列出了文件夹中的所有 Excel 文件。然后我尝试运行 ImportExcel 模块中的一个命令,将第一个工作表重命名为“Sheet1”。

foreach ($i in $file )
{
$xl= Open-ExcelPackage $file
$sheet1 = $xl.Workbook.Worksheets[1]
$sheet1.Name ="Sheet1"
Close-ExcelPackage $xl
}

但是当我运行这段代码时,文件夹中的每个文件都会出现以下错误:

WARNING: Could not find C:\WINDOWS\system32\11.25.2020_JH_BDX.xlsx 11.25.2020_JH_COV.xlsx 11.25.2020_JH_MISC.xlsx bx_1_coverage_report_2020-11-25 Final V.1 .xlsx bx_2_misc_report_2020-11-25 Final V.1 .xlsx bx_3_bordereau_report_2020-11-25 Final. V.1 .xlsx ic
at_cov_20201126053019.xlsx icat_misc_20201126053024.xlsx
Cannot index into a null array.
At line:8 char:1
+ $sheet1 = $xl.Workbook.Worksheets[1]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray
 
Close-ExcelPackage : Cannot bind argument to parameter 'ExcelPackage' because it is null.
At line:10 char:20
+ Close-ExcelPackage $xl
+                    ~~~
    + CategoryInfo          : InvalidData: (:) [Close-ExcelPackage], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Close-ExcelPackage

如果我在 32 位而不是 64 位中运行,它看起来像是在这里寻找文件:

WARNING: Could not find C:\Users\1192643\11.25.2020_JH_BDX.xlsx 11.25.2020_JH_COV.xlsx 11.25.2020_JH_MISC.xlsx bx_1_coverage_report_2020-11-25 Final V.1 .xlsx bx_2_misc_report_2020-11-25 Final V.1 .xlsx bx_3_bordereau_report_2020-11-25 Final. V.1 .xlsx icat_
cov_20201126053019.xlsx icat_misc_20201126053024.xlsx

我不确定它为什么要在 C:\WINDOWS\system32 或我的用户主管中查找 Excel 文件。我已尝试通过在 foreach 块中添加完整路径来确保它位于正确的文件夹中:

foreach ($i in $file )
{
$xl= Open-ExcelPackage "C:\PowerShell\BA\"$file
$sheet1 = $xl.Workbook.Worksheets[1]
$sheet1.Name ="Sheet1"
Close-ExcelPackage $xl
}

但这也不起作用。谁能帮我理解我在这里缺少什么?我的版本是 5.1.17763.1490。

$xl 变量更新为$xl= Open-ExcelPackage $i.fullname 会出现以下错误 - 所以它现在似乎有正确的路径,但它不喜欢代码。 Open-ExcelPackage:无法将参数绑定到参数“路径”,因为它为空。 在 C:\PowerShell\BA\RenameWorksheet.ps1:23 char:24 + $xl= Open-ExcelPackage $i.fullname + ~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [Open-ExcelPackage], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Open-ExcelPackage

Cannot index into a null array.
At C:\PowerShell\BA\RenameWorksheet.ps1:24 char:1
+ $sheet1 = $xl.Workbook.Worksheets[1]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray
 
The property 'Name' cannot be found on this object. Verify that the property exists and can be set.
At C:\PowerShell\BA\RenameWorksheet.ps1:25 char:1
+ $sheet1.Name ="Sheet1"
+ ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound
 
Close-ExcelPackage : Cannot bind argument to parameter 'ExcelPackage' because it is null.
At C:\PowerShell\BA\RenameWorksheet.ps1:26 char:20
+ Close-ExcelPackage $xl
+                    ~~~
    + CategoryInfo          : InvalidData: (:) [Close-ExcelPackage], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Close-ExcelPackage

为了测试代码,我可以使用以下方法更新特定 .xlsx 文件中的工作表名称:

$xl= Open-ExcelPackage "C:\PowerShell\BA\11.25.2020_JH_MISC.xlsx"
$sheet1 = $xl.Workbook.Worksheets[1]
$sheet1.Name ="Sheet1"
Close-ExcelPackage $xl

谢谢,

【问题讨论】:

  • 尝试将您的 $xl 更改为 $xl= Open-ExcelPackage $i.fullname
  • get-childitem 上的name 参数只返回文件名。将其更改为 -filter。那么你可能需要使用 $file.fullname

标签: powershell


【解决方案1】:

不要在循环内引用 $file。如果您正在寻找其中一个文件的句柄,请使用 $i,因为这是您在 foreach 设置中选择的名称。请注意,我已将 $i 放在带引号的字符串中。

foreach ($i in $file )
{
$xl= Open-ExcelPackage "C:\PowerShell\BA\$i"
$sheet1 = $xl.Workbook.Worksheets[1]
$sheet1.Name ="Sheet1"
Close-ExcelPackage $xl
}

【讨论】:

    【解决方案2】:

    使用 PowerShell 时,有两点需要记住。

    1. PowerShell 是面向对象的。
    2. PowerShell 使用管道。

    这里我们有一个变量和一个循环。两者都可以通过切换到管道来消除。

    请注意阅读Get-ChildItem 的帮助文件。

    正如 Doug 所说,-Name 参数:

    -名称

    仅获取位置中项目的名称。输出是一个字符串对象,可以沿着管道发送到其他命令。允许使用通配符。

    这里我们从FileInfo 对象转到String。所以我们丢失了有价值的信息,比如每个文件的位置:$_.FullName这导致了$i.fullname的问题

    另外,-Include-Path 中需要一个特殊的通配符。

    -包括

    以字符串数组的形式指定此 cmdlet 在操作中包含的一个或多个项目。此参数的值限定了 Path 参数。输入路径元素或模式,例如“*.txt”。允许使用通配符。 Include参数仅在命令包含某项内容时有效,例如C:\Windows\*,其中通配符指定C:\Windows目录的内容。

    Get-ChildItem 不会产生任何输出,除非您遵循此模式或(出于某种原因)包含 -Name 参数。这可能就是您一开始使用-Name 参数的原因。

    最终答案

    Get-ChildItem -Path "C:\PowerShell\BA\*" -Include "*.xlsx" | 
      ForEach-Object { 
        $xl = Open-ExcelPackage $_.FullName
        $sheet1 = $xl.Workbook.Worksheets[1]
        $sheet1.Name ="Sheet1"
        Close-ExcelPackage $xl
      }
    

    如果您有大量文件并且能够安装 PowerShell 7,则可以使用 -Parallel 参数来加快处理速度。

    Get-ChildItem -Path "C:\PowerShell\BA\*" -Include "*.xlsx" | 
      ForEach-Object -Parallel { 
        $xl = Open-ExcelPackage $_.FullName
        $sheet1 = $xl.Workbook.Worksheets[1]
        $sheet1.Name ="Sheet1"
        Close-ExcelPackage $xl
      } -ThrottleLimit 5
    

    如果您不是本地管理员,则可以从应用商店获取 PowerShell 7。

    解释错误消息

    C:\WINDOWS\system32\$env:USERPROFILE 是加载 PowerShell 时的默认工作目录。

    看看我们的路:

    C:\WINDOWS\system32\11.25.2020_JH_BDX.xlsx
    

    我们有一个默认目录和一个自定义文件。

    这表明我们只是为我们的函数提供文件名。例如。 $_.Name

    在我们的例子中,这个错误的根本原因是Get-ChildItem -Name,它只生成文件名作为字符串。有必要按 Walter 限定这些文件名。或者删除 -Name 并使用 FileInfo per Doug / Itchydon 的 FullName 属性。


    Open-ExcelPackage:无法将参数绑定到参数“路径”,因为它为空。
    $xl= Open-ExcelPackage $i.fullname

    这里有两条线索。

    一个,我们只是改变了

    $xl= Open-ExcelPackage $file
    

    $xl= Open-ExcelPackage $i.fullname
    

    所以,$i.fullname 一定是问题所在。

    二,我们可以追溯错误信息的逻辑。

    it is null -> parameter 'Path' -> Open-ExcelPackage Cannot bind -> Open-ExcelPackage $i.fullname

    最有可能的两种可能性是$i$i.FullName 从一开始就不存在。

    如果我们检查,我们会看到 $i 没有 FullName 属性。

    调试

    在脚本文件中为$xl= Open-ExcelPackage $i.fullname 行设置断点。

    例如,

    1  # C:\users\michael\desktop\vim\demo 1.ps1
    2  $file = Get-ChildItem -Path "C:\users\michael\desktop\vim" -Name -Include *.out
    3  
    4  
    5  foreach ($i in $file )
    6  {
    7  $xl= Open-ExcelPackage $i.fullname
    8  $sheet1 = $xl.Workbook.Worksheets[1]
    9  $sheet1.Name ="Sheet1"
    10 Close-ExcelPackage $xl
    11 }
    
    > # from the shell
    > Set-PSBreakpoint -Script '.\demo 1.ps1' -Line 7
    
      ID Script            Line Command           Variable         Action
      -- ------            ---- -------           --------         ------
       0 demo 1.ps1           7
    
    > & '.\demo 1.ps1'
    Entering debug mode. Use h or ? for help.
    
    Hit Line breakpoint on 'C:\Users\Michael\desktop\vim\demo 1.ps1:7'
    
    At C:\Users\Michael\desktop\vim\demo 1.ps1:7 char:1
    + $xl= Open-ExcelPackage $i.fullname
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    > $i | gm
    
       TypeName: System.String
    
    Name             MemberType            Definition
    ----             ----------            ----------
    Clone            Method                System.Object Clone(), System.Object ...
    CompareTo        Method                int CompareTo(System.Object value), i...
    Contains         Method                bool Contains(string value)
    ...
    
    > # We have a string. 
    
    > $i | Get-Member | Where-Object { $_.name -match "^f" }
    > # No match for properties starting with the letter 'f'. 
    > # So, strings don't have a 'FullName' property. 
    > q # to quit the debugger
    

    无法将参数绑定到参数“路径”...
    无法索引到空数组。
    在此对象上找不到属性“名称”...
    Close-ExcelPackage : 无法绑定参数...

    解决第一个错误通常会修复代码或使更大的问题变得明显。

    例如,我们知道如果 $xl= Open-ExcelPackage $i.fullname 不起作用,$sheet1 = $xl.Workbook.Worksheets[1](取决于定义的 $xl)将不起作用。

    在第一个错误得到解决之前,查看第二个、第三个、第四个等错误没有多大意义。

    管道

    关于pipelines 需要了解的两点是:

    1. Cmdlet 与管道 | (ASCII 124) 和
    2. automatic variable 用于表示当前正在处理的对象:$_

    这为我们提供了连接 cmdlet cmdlet | cmdlet 和引用当前正在处理的对象的属性 ForEach-Object { $_.FullName } 的基本工具

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-25
      • 2021-11-22
      • 1970-01-01
      • 2017-04-17
      • 2020-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多