2

I'm writing an archiving script which collecting desired files to an array then adding them to an archive 1 by 1.

I came to a problem when there is DIR1/file.ext and DIR2/file.ext because DIR2's file going to overwrite the previous.

How can I set unique filename or how it's possible to solve it on the fly instead of copying files to a dir with structures then zip the whole dir?

Here is my code:

# GET FILE LIST
$outgoingfiles =  Get-ChildItem -Depth 1 -Filter "*.EXT" | Where-Object { $_.DirectoryName -like "*OUTGOING*" }

# Handle if OUTGOING/archive dir is exists
if(-not (Test-Path "OUTGOING/archive")) {
       New-Item -Path "OUTGOING/archive" -ItemType Directory 
}

# ZIP outgoing files
ForEach ($outgoing in $outgoingfiles) {
    Compress-Archive $outgoing.FullName -Update -DestinationPath $zippath
}

Thank you!

5
  • Are the file names important at all - eg. do they need to be preserved? Commented Apr 7, 2020 at 12:28
  • So from my understanding, you want to copy all same name files to a flat directory without preserving folders, but you want make sure the files don't overwrite each other. Commented Apr 7, 2020 at 12:41
  • Original filename must be kept but it can extended for example with the original parent dir so DIR1\file.ext can be dir1_file.ext in the archive. Preserving directories in the archive also good. Commented Apr 7, 2020 at 13:03
  • I guess the other way is embedding timestamps into the filename, but that could be risky because two files could have been created at the same time. Commented Apr 7, 2020 at 13:06
  • How can I manipulate filename in the archive at this code? Compress-Archive $outgoing.FullName -Update -DestinationPath $zippath Commented Apr 7, 2020 at 13:13

2 Answers 2

1

I don't think there is a way to tell Compress-Archive to rename files when a file with the same name is already included in the zip.

What you can do is create a temporary folder, copy all files to there and if needed rename them. Then create the zip file using the unique files in that folder. Finally, remove the temp folder again:

$zippath  = 'D:\Test\OutGoing.zip'  # path and filename for the output zip file
$rootPath = 'D:\Test'               # where the files can be found

# create a temporary folder to uniquely copy the files to
$tempFolder = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([Guid]::NewGuid().Guid)
$null = New-Item -ItemType Directory -Path $tempFolder
# create a hashtable to store the fileHash already copied
$fileHash = @{}

# get the list of files and copy them to a temporary folder
Get-ChildItem -Path $rootPath -Depth 1 -Filter '*.EXT' -File | Where-Object { $_.DirectoryName -like "*OUTGOING*" } | ForEach-Object {
    $count = 1
    $newName = $_.Name
    # test if the file name is already in the hash and if so, append a counter to the basename
    while ($fileHash.ContainsKey($newName)) {
        $newName = "{0}({1}){2}" -f $_.BaseName, $count++, $_.Extension
    }
    # store this file name in the hash and copy the file
    $fileHash[$newName] = $true
    $newFile = Join-Path -Path $tempFolder -ChildPath $newName
    $_ | Copy-Item -Destination $newFile -Force
}

# append '*.*' to the temporary folder name.
$path = Join-Path -Path $tempFolder -ChildPath '*.*'
# next, get the list of files in this temp folder and start archiving
Compress-Archive -Path $path -DestinationPath $zippath -Update

# when done, remove the tempfolder and files
Remove-Item -Path $tempFolder -Force -Recurse

Hope that helps

Sign up to request clarification or add additional context in comments.

1 Comment

I like this answer. Shows how to make the filenames unique, which is a good way to do it if my lazier approach is not sufficient. +1
0

I would just copy the files along with their parent directories to a destination folder, then zip it up with Compress-Archive. Then you don't have to worry about making filenames unique.

Demo:

$sourceFolder = "C:\\"
$destinationFolder = "C:\\OUTGOING"

# Create destination folder if it doesn't exist
if (-not(Test-Path -Path $destinationFolder -PathType Container))
{
    New-Item -Path $destinationFolder -ItemType Directory
}

# Get all .exe files one level deep
$files = Get-ChildItem -Path $sourceFolder -Depth 1 -Filter *.ext

foreach ($file in $files)
{
    # Get standalone parent directory e.g. DIR1, DIR2
    $parentFolder = Split-Path -Path (Split-Path -Path $file.FullName) -Leaf

    # Create destination path with this parent directory
    $destination = Join-Path -Path $destinationFolder -ChildPath $parentFolder

    # Create destination parent directory if it doesn't exist
    if (-not(Test-Path -Path $destination -PathType Container))
    {
        New-Item -Path $destination -ItemType Directory
    }

    # Copy file to parent directory in destination
    Copy-Item -Path $file.FullName -Destination $destination
}

# Zip up destination folder
# Make sure to pass -Update for redoing compression
Compress-Archive -Path $destinationFolder -DestinationPath "OUTGOING.zip" -Update -CompressionLevel Optimal

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.