Take files from txt file in packages to zip them

Hi,
I am trying to achieve following with powershell script:
Got folder A where txt and png files are placed (1.txt, 1.png, 2.txt, 2.png etc). I want powershell script to do following:

  1. search for ready.txt file in folder
  2. when ready file is there retrieve list of files to zip from ready.txt count them and check if that matches count of txt and png in folder
  3. create subfolders and move files there: packages for 1000 each but pairs have to be in same folders: 1.txt have to be in folder with 1.png
  4. zip all and move to folder

I am stuck on 3 and 4. Guess proper loop is needed. What i got so far:

$location=“C:\A”
$strFileName=“ready.txt”
$archive=“C:\B”

function fileready
{
while (!(Test-Path $location$strFileName)) {Start-Sleep -s 5}
}

$readyfile = Get-ChildItem -Recurse -include $strFileName

[int]$readyfilecount = (Get-Content $readyfile | Measure-Object).Count
$readyfilecount

[int]$folderfilescount = (Get-ChildItem -Recurse -path $location -include @(“.txt",".png”)).Count
$folderfilescount

If ($readyfilecount -eq $folderfilescount)
{

}
else
{
fileready
}

Thx for any suggestions!

A part of your question confuses me. Does this ready.txt file contain just a list of filenames or paths that need to be moved?

This will create folders, move files to specific folders, and create a zip archive for every 1000 folders containing your files. This script uses 7zip Portable to create the archives. I now realize how powerful and easy a switch statement is compared to cumbersome nested If/foreach statements. Thank you for the challenge.

$source = "C:\FolderA\"
$dest = "C:\FolderB\"
$files = Get-ChildItem -Path $source -Recurse -Include "*.png","*.txt","readyfile.txt"
$readyfile = $files -match 'readyfile.txt'
$7zip = Read-Host 'Where is 7zip (7z.exe)?'

# Create folders and move files to folders
Write-Verbose 'Copying files to new folders' -Verbose
foreach ($file in ($files -notmatch 'readyfile.txt')){
$basename = "$source$($file.basename)"
new-item -ItemType Directory $basename -ErrorAction SilentlyContinue
move-item -Path $file.FullName -Destination $basename -ErrorAction SilentlyContinue}

# Cast and sort folder names (numbers)
Write-Verbose 'Getting list of new folders' -Verbose
$folders = Get-ChildItem -Path $source -Directory -Recurse
$fsort = $folders | foreach {$_.Name -as [int]} | Sort-Object

# Add folders to zip archives
switch ($fsort){
1 {$dir = 1000; If (!(Test-Path "$($source)1000")){
New-Item -ItemType Directory "$($source)1000" -ErrorAction SilentlyContinue}}
{($_ % 1000 -eq 0) -or ($_ -eq 1000)} 
{$dir = $_; Start-Process $7zip -ArgumentList "a `"$dest$dir.zip`" `"$source$_`"" -WindowStyle Hidden -Wait}
{(($_ -le 1000) -and ($_ % 1000 -ne 0)) -or (($_ -gt 1000) -and ($_ % 1000 -ne 0))} 
{Write-Verbose "Copying folder $_ to archive" -Verbose
Start-Process $7zip -ArgumentList "a `"$dest$dir.zip`" `"$source$_`"" -WindowStyle Hidden -Wait}
} 

You can use the builtin COM shell.application object, but I found it to be limited in function. I could not suppress COM progress bars, force asynchronous transfer (wait for previous file transfer), etc. Below is an example of what I tried with COM.

$shell = ( new-object -com shell.application ).NameSpace( $folder.FullName )
$zipshell = ( new-object -com shell.application ).NameSpace( $ziplocation )
$zipshell.CopyHere($folder.FullName) 

There are a couple of other options for creating the zip file:

PowerShell version 5 adds native support for ZIP files.

For older versions, the PowerShell Community Extensions (pscx) can be used to add ZIP file support by way of the Write-ZIP cmdlet.

Hi,

Thx for replies. To clarify this: there is a txt file with only filenames to zip. Lets say there is 2500 filenames there, It should only create 3 subfolders and zip them. So for 1000 files create subfolder, another 1000 files create subfolder, last 500 files create subfolder. Will have a look random commandline on your code.

Regards

I understand now. I modified my script above, this should work for you. Output will display what files were moved and if a filename in the text does not exist in the folder.
I choose to use the builtin ZipFile .NET class discussed here. The page states the .NET class was introduced with .NET 4.5, but it worked with my 4.0 install.

# Get files
$source = "C:\A"
$movefolders = "C:\A\MoveFolders"
$dest = "C:\B"
Write-Verbose "Getting list of files" -Verbose
$files = Get-ChildItem -Recurse -Include "*.png","*.txt" -Path $source 
$ready = Get-ChildItem $source -Filter 'ready.txt'

# Move every 1000 files to a folder
$count = 0 ; $readyfile = $ready.OpenText()
while ($readyfile.EndOfStream -eq $false){
switch ($readyfile.ReadLine()){
$_ {$count++;$num=$_; If ($count -eq 1){$newdir = 1000 ; 
    New-Item -ItemType Directory -Path "$movefolders\$newdir" -ErrorAction SilentlyContinue}}
# Match each line in ready.txt with files
$_ {If ($match = $files | where {$_.BaseName -eq $num}){$match | 
    move-Item -Destination "$movefolders\$newdir" ; 
    Write-Verbose "Moving file $num to $movefolders\$newdir !!!" -Verbose} Else 
    {Write-Verbose "$num not found" -Verbose}}
$_ {If ($count % 1000 -eq 0){$newdir = $count+1000 ; 
    new-item -ItemType Directory -Path "$movefolders\$newdir" -ErrorAction SilentlyContinue}}
} # End switch
} # End while

# Add folders to zip archive
add-type -AssemblyName 'System.IO.Compression.filesystem'
Write-Verbose "Creating archive" -Verbose
[System.IO.Compression.ZipFile]::CreateFromDirectory($movefolders,"$dest\Archive.zip")