ZipFolders.ps1
|
<# .SYNOPSIS Compresses all first-level subfolders within a specified parent folder into individual ZIP archives using 7-Zip. .DESCRIPTION Used this for archiving to the archive drive. This script takes a parent folder path as an argument. It iterates through all immediate subdirectories within that parent folder. Each subdirectory is then compressed into its own .zip file, named after the subdirectory, and saved in the user's Downloads folder. You must have 7-Zip installed for this script to work. .PARAMETER ParentFolderPath The full path to the folder containing the subfolders you want to compress. .EXAMPLE .\Compress-SubFolders.ps1 -ParentFolderPath "C:\MyProjects" This will find all subfolders directly under C:\MyProjects (e.g., C:\MyProjects\ProjectA, C:\MyProjects\ProjectB) and create ProjectA.zip and ProjectB.zip in the Downloads folder. .NOTES Author: GitHub Copilot Date: 2025-05-12 Ensure 7-Zip is installed and the path to 7z.exe is correct or 7z.exe is in your system PATH. #> param ( [Parameter(Mandatory=$true, ValueFromPipeline=$false)] [string]$ParentFolderPath ) # --- Configuration: 7-Zip Path --- $sevenZipExePaths = @( "C:\Program Files\7-Zip\7z.exe", # Common 64-bit install path "C:\Program Files (x86)\7-Zip\7z.exe" # Common 32-bit install path ) $sevenZipExe = $null foreach ($path in $sevenZipExePaths) { if (Test-Path $path -PathType Leaf) { $sevenZipExe = $path break } } if (-not $sevenZipExe) { if (Get-Command 7z.exe -ErrorAction SilentlyContinue) { $sevenZipExe = "7z.exe" # Found in PATH Write-Host "Using 7z.exe found in system PATH." } else { Write-Error "7-Zip executable (7z.exe) not found. Please install 7-Zip or ensure it's in your system PATH." Write-Error "Checked paths: $($sevenZipExePaths -join ', ') and system PATH." exit 1 } } else { Write-Host "Using 7-Zip at: $sevenZipExe" } # --- Get Downloads Folder --- try { $downloadsFolder = [IO.Path]::Combine($env:USERPROFILE, "Downloads") if (-not (Test-Path $downloadsFolder -PathType Container)) { Write-Error "Downloads folder not found at '$downloadsFolder'." exit 1 } # Create a subfolder named "ZipArchives" inside Downloads $archivesFolder = [IO.Path]::Combine($downloadsFolder, "ZipArchives") if (-not (Test-Path $archivesFolder -PathType Container)) { New-Item -ItemType Directory -Path $archivesFolder | Out-Null } # Create a folder named after the source folder in the ZipArchives folder $sourceFolderName = [IO.Path]::GetFileName($ParentFolderPath.TrimEnd('\')) $outputFolder = [IO.Path]::Combine($archivesFolder, $sourceFolderName) # Ensure the folder name is unique by appending a numeric identifier if necessary $counter = 1 while (Test-Path $outputFolder -PathType Container) { $outputFolder = [IO.Path]::Combine($archivesFolder, "$sourceFolderName ($counter)") $counter++ } New-Item -ItemType Directory -Path $outputFolder | Out-Null Write-Host "Outputting ZIP files to: $outputFolder" } catch { Write-Error "Error getting Downloads folder path: $($_.Exception.Message)" exit 1 } # --- Validate Parent Folder --- if (-not (Test-Path $ParentFolderPath -PathType Container)) { Write-Error "The specified parent folder does not exist or is not a directory: '$ParentFolderPath'" exit 1 } # --- Get First-Level Subfolders --- $subFolders = Get-ChildItem -Path $ParentFolderPath -Directory -ErrorAction SilentlyContinue if (-not $subFolders) { Write-Warning "No subfolders found in '$ParentFolderPath'." exit 0 } Write-Host "Found the following subfolders to compress in '$ParentFolderPath':" $subFolders | ForEach-Object { Write-Host "- $($_.Name)" } Write-Host "" # Newline for better readability # --- Process Each Subfolder Concurrently --- $maxConcurrentJobs = 4 $jobs = @() # Initialize as a standard PowerShell array foreach ($folder in $subFolders) { # Wait if the number of running jobs reaches the limit while (($jobs | Where-Object { $_.State -eq 'Running' }).Count -ge $maxConcurrentJobs) { $runningJobsCount = ($jobs | Where-Object { $_.State -eq 'Running' }).Count Write-Host "Waiting for available job slots... Running jobs: $runningJobsCount" Start-Sleep -Seconds 1 } $folderName = $folder.Name $folderFullPath = $folder.FullName $zipFileName = "$($folderName).zip" $outputZipPath = Join-Path -Path $outputFolder -ChildPath $zipFileName Write-Host "Starting compression for folder: $folderName" # Start a new job for compressing the folder $job = Start-Job -ScriptBlock { param ($sevenZipExe, $folderFullPath, $outputZipPath) $arguments = @( "a", "-tzip", "-r", "`"$outputZipPath`"", "`"$folderFullPath\*`"" ) try { # Run the 7-Zip process without redirecting output $process = Start-Process -FilePath $sevenZipExe -ArgumentList $arguments -Wait -NoNewWindow -PassThru if ($process.ExitCode -eq 0) { Write-Output "Successfully compressed '$folderFullPath' to '$outputZipPath'." } else { Write-Output "7-Zip process exited with code $($process.ExitCode) for folder '$folderFullPath'." } } catch { Write-Output "Error running 7-Zip for folder '$folderFullPath': $($_.Exception.Message)" } } -ArgumentList $sevenZipExe, $folderFullPath, $outputZipPath $jobs += $job # Append the job to the array } # Wait for all jobs to complete Write-Host "Waiting for all compression jobs to complete..." while (($jobs | Where-Object { $_.State -eq 'Running' }).Count -gt 0) { $runningJobsCount = ($jobs | Where-Object { $_.State -eq 'Running' }).Count Write-Host "Running jobs: $runningJobsCount" Start-Sleep -Seconds 1 } # Clean up completed jobs $jobs | ForEach-Object { # $jobOutput = Receive-Job -Job $_ -Wait # Write-Host $jobOutput Remove-Job -Job $_ } # Copy files from the parent folder to the output folder Write-Host "Copying files from parent folder to output folder..." $parentFolderFiles = Get-ChildItem -Path $ParentFolderPath -File -ErrorAction SilentlyContinue if ($parentFolderFiles) { foreach ($file in $parentFolderFiles) { $destinationPath = Join-Path -Path $outputFolder -ChildPath $file.Name try { Copy-Item -Path $file.FullName -Destination $destinationPath -Force Write-Host "Copied file: $($file.Name) to $outputFolder" } catch { Write-Error "Failed to copy file: $($file.Name). Error: $($_.Exception.Message)" } } } else { Write-Host "No files found in the parent folder to copy." } Write-Host "All folders have been compressed. Total: $($jobs.Count)" Write-Host "ZIP files are located in: $outputFolder" |