【问题标题】:Referring to Files as variables in multiple ForEach loops [PowerShell]在多个 ForEach 循环中将文件称为变量 [PowerShell]
【发布时间】:2021-12-02 18:28:24
【问题描述】:

我在我的脚本上取得了一些进展,该脚本会自动更新 excel 文件中的链接而无需打开它们。我已经成功地使该函数在单个文件上工作,并输入文件名和要替换的文本。现在我正在尝试扩展它,以便它对脚本目录中的所有文件执行相同的操作。

以下是脚本在步骤中与 cmets 的搭配方式:

# This part will be responsible from fetching the week number to replace from the script directory name, currently I am testing with pre-determined number
# $wk = Get-Item -Path $PWD | Select-Object -Property BaseName
# $wknn = "$wk".Substring(13,2) -as [int]
$wknn = 41
$wkold = $wknn-1
$wkprev = $wknn-2
$DefaultFiles =  Get-ChildItem | Where-Object {$_.Name -like "*.xls*"}
ForEach($File in $DefaultFiles) 
{

    # Build ZIP file name
    $zipFile =  $_ -ireplace [regex]::Escape(".xlsb"), ".zip"

    # Create temporary folder
    $parent = [System.IO.Path]::GetTempPath();
    [string] $guid = [System.Guid]::NewGuid();
    $tempFolder = Join-Path $parent $guid;
    New-Item -ItemType Directory -Path $tempFolder;

    # Rename file to ZIP
    Rename-Item -Path $_ -NewName $zipFile

    # Not using Expand-Archive because it changes the ZIP format
    C:\7z\7za.exe x "$zipFile" -o"$tempFolder"
    
    # Replace old text with new text. First replace wk-1 to wk and then wk-2 to wk-1
    $fileNames = Get-ChildItem -Path $tempFolder -Recurse -Include *.rels
    foreach ($file in $fileNames)
    {
        (Get-Content -ErrorAction SilentlyContinue $file.FullName) |
        Foreach-Object { $_ -replace $wkold, $wknn } |
        Foreach-Object { $_ -replace $wkprev, $wkold } |
        Set-Content $file.FullName
    }

     # Changing working folder because 7Zip option -w doesn't work
    Set-Location -Path $tempfolder

    # Update archive with new files. Not using Compress-Archive because it changes the ZIP format
    C:\7z\7za.exe u -r "$zipFile" *.*

    # Rename file back to XLSB
    Rename-Item -Path $zipFile -NewName $_
    
    #Move the final .xlsb file back to the script root
    move-Item -Path $_ -destination $PSScriptRoot
    
    #Set location to script root to start over
    Set-Location -Path $PSScriptRoot
    }
}

我遇到了 forEach 循环的问题。我不确定如何在 Build Zip File Name 步骤的第一个循环中引用文件名。之后我想将输出文件移动到脚本根目录时如何引用它。此外,我怀疑 forEach 循环的堆叠可能不那么简单,并且需要在代码中执行额外的步骤,但由于我刚开始使用 C 语言,我没有经验,无法找到我的问题的简单答案。

我非常感谢您对我的代码中的语法提供一些帮助 :)

【问题讨论】:

  • $file.Name,尽管您可能希望在外部或内部 foreach 循环中重命名 $file 变量

标签: excel powershell zip


【解决方案1】:

我会在主循环外部创建一个临时文件夹,并将工作目录设置为该文件夹。然后删除文件夹并在所有完成后重置工作目录。

此外,无需先重命名已完成的 zip 文件,然后再将其移回其原始位置,因为您可以同时使用 Move-Item cmdlet 来执行此操作。

试试:

$wknn       = 41
$wkold      = $wknn - 1
$wkprev     = $wknn - 2

$7zipExe    = 'C:\7z\7za.exe'  # path to 7za.exe
$sourcePath = $PSScriptRoot    # path to where the Excel files are

# Create temporary folder
$tempFolder = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ((New-Guid).Guid)
$null       = New-Item -ItemType Directory -Path $tempFolder -Force

# retrieve a collection of Excel files (FullNames only). 
# If you ONLY want .xlsb files, set the Filter to '*.xlsb'
$excelFiles = (Get-ChildItem -Path $sourcePath -Filter '*.xls*' -File).FullName

# Changing working folder because 7Zip option -w doesn't work
Set-Location -Path $tempfolder

foreach($File in $excelFiles) {
    # Build ZIP file name
    $zipFile = [System.IO.Path]::ChangeExtension($File, '.zip')

    # Rename file to ZIP
    Rename-Item -Path $File -NewName $zipFile

    # Not using Expand-Archive because it changes the ZIP format
    & $7zipExe x "$zipFile" -o"$tempFolder" | Out-Null

    # Replace old text with new text. First replace wk-1 to wk and then wk-2 to wk-1
    Get-ChildItem -Path $tempFolder -Recurse -Filter '*.rels' -File | ForEach-Object {
        (Get-Content -Path $_.FullName -Raw) -replace $wkold, $wknn -replace $wkprev, $wkold |
        Set-Content $_.FullName
    }

    # Update archive with new files. Not using Compress-Archive because it changes the ZIP format
    & $7zipExe u -r "$zipFile" *.* | Out-Null

    # Rename and Move the updated file back to the original location (overwrite)
    Move-Item -Path $zipFile -Destination $File -Force

    # remove all files from the temporary folder to start fresh
    Remove-Item -Path "$tempfolder\*" -Recurse -Force
}

# Set location back to script root
Set-Location -Path $PSScriptRoot
# remove the temporary folder
Remove-Item -Path $tempfolder -Recurse -Force

【讨论】:

  • 您大大提高了我的流程效率!谢谢西奥!我还可以寻求进一步的建议吗?出于某种原因,我发现我的脚本仅在尝试替换整数时才有效。这带来了一个问题,对于大型工作簿,许多错误的数字会被更改,从而破坏工作簿。我试图更改变量以使其成为“wk41”格式$wknn = "$wk".Substring(13,2) -as [int] $wknew = write-host "wk$wknn" $wkoldnum = $wknn-1 $wkold = write-host "wk$wkoldnum" $wkprevnum = $wknn-2 $wkprev = write-host "wk$wkprevnum" 的字符串,但这会破坏脚本。
  • @Kuzed 从您的原始代码中,您尝试从$PWD 获取星期数$wk,这是当前工作目录(可能类似于C:\Users\Kuzed)。你确定你做对了吗?那不应该是当前的脚本路径$PSScriptRoot 吗? *.rels 文件实际上是 XML 文件,因此最好检查它们以查看哪些标签或属性需要以正确的“XML”方式更新,而不是仅在这些数字上使用 -replace。你能显示rels 文件之一?
  • 我从路径的最后部分获取数字,它以“example/wk41/”结尾,因此它从文件夹中获取 41 数字。
  • .rels 文件在Target = "file location" 参数中包含有关外部链接的信息。 .rels 文件内容示例:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath" Target="/RU/d_Finance/Common/e-commerce/2021/Action%20plan/wk39/e-com_approx_wk39.xlsb" TargetMode="External"/></Relationships>
  • 我正在尝试替换路径中的 /wk39/ 部分和文件名中的“wk39”部分。想法是将 Wk-1 更新为 Current Wk,然后在所有 .rels 目标中将 Wk-2 更新为 Wk-1
猜你喜欢
  • 2011-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-14
相关资源
最近更新 更多