Home > database >  Referring to Files as variables in multiple ForEach loops [PowerShell]
Referring to Files as variables in multiple ForEach loops [PowerShell]

Time:10-15

Im am making some progress on my script that automatically updates links in excel files without opening them. I have successfully made the function work on a single file with inputs of file name and text to replace. Now I am trying to scale this so that it does the same actions for all files in the script directory.

Here is how the script goes with comments on steps:

# 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
    }
}

I am running into problems with the forEach loop. I am unsure on how do I refer to the file name within the first loop at the Build Zip File Name step. And how do I refer to the output file when i Want to move it to the script root afterwards. Also I suspect that stacking of forEach loops may be not as simple and require extra steps within the code, but due to me just starting out in C I dont have the experience and could not find a simple answer to my problem.

I would really appreciate some assistance with the syntax in my code :)

CodePudding user response:

I would create a temporary folder outside the main loop and set the working directory to that folder. Then remove the folder and reset the working directory when all is done.

Also, there is no need to rename the finished zip file first and then move it back to its original location, because you can do that with the Move-Item cmdlet at the same time.

Try:

$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
  • Related