Home > Software engineering >  Using Compress-Archive to compress multiple folders multithreadded with Powershell
Using Compress-Archive to compress multiple folders multithreadded with Powershell

Time:10-22

Everyday I need create archives of the following

C:.
└───1.Jan
    ├───20000
    │       img1.bmp
    │       img2.bmp
    │       img3.bmp
    │
    ├───20001
    │       img1.bmp
    │       img2.bmp
    │       img3.bmp
    │
    ├───20002
    │       img1.bmp
    │       img2.bmp
    │       img3.bmp
    │
    ├───20003
    │       img1.bmp
    │       img2.bmp
    │       img3.bmp
    │
    ├───20004
    │       img1.bmp
    │       img2.bmp
    │       img3.bmp
    │
    ├───20005
    │        img1.bmp
    │        img2.bmp
    │        img3.bmp
    │
    └───Entered

I currently have the script working with creating the zip files one at a time, However I can sometimes have 200 folders to zip and they are different sizes so I would like to get this working multithreadded.

function Zip-Folders([String] $FolderPath) {
if ($FolderPath -eq '') {
    return
} 
else {
    $FolderNames = Get-ChildItem -Path $FolderPath -Name -Directory -Exclude Enter*
        foreach ($i in $FolderNames) {
            $TempPath = "$FolderPath\$i"
            $TempFileName = "$i Photos"
            if (-Not(Get-ChildItem -Path $TempPath | Where-Object {$_.Name -like '*.zip'})) {
                Write-Host "[$TempPath] has been compressed to [$TempFileName]."
                Compress-Archive -Path $tempPath\* -DestinationPath $tempPath\$TempFileName
            }
            Else {
                Write-Host "[$i] has already been compressed."
            }
        }
}
}

The code asks for the folder via a Folderbrowser dialog.

If someone could either help with the code or point me in the direction where I can find the information for this, I am a beginner with PowerShell but have done some programming.

If there is any other information needed let me know.

CodePudding user response:

This is how you can do it using Runspace, use the -Threshold argument depending on how many folders you want to compress at the same time. Watch your host resources and use with care :)

All credits on the Runspace code go to this answer.

function Zip-Folders {
param(
    [ValidateScript({Test-Path $_ -PathType Container})]
    [String]$FolderPath,
    [int]$Threshold = 10
)
    begin
    {
        $RunspacePool = [runspacefactory]::CreateRunspacePool(1, $Threshold)
        $RunspacePool.Open()
        $subFolders = Get-ChildItem -Path $FolderPath -Directory -Exclude Enter*
    }
    
    process
    {
        $runspaces = foreach ($folder in $subFolders)
        {
            $PSInstance = [powershell]::Create().AddScript({
                param($thisFolder)

                $fileName = "{0} Photos.zip" -f $thisFolder.Name
                $absolutePath = $thisFolder.FullName
                $zipPath = Join-Path $absolutePath -ChildPath $fileName

                if(-not(Get-ChildItem -Path $absolutePath -Filter *.zip))
                {
                    Compress-Archive -Path $absolutePath\* -DestinationPath $zipPath
                    "[$absolutePath] has been compressed to [$zipPath]."

                    continue
                }

                "[$absolutePath] has already been compressed."

            }).AddParameter('thisFolder',$folder)

            $PSInstance.RunspacePool = $RunspacePool

            [pscustomobject]@{
                Instance = $PSInstance
                IAResult = $PSInstance.BeginInvoke()
            }
        }

        while($runspaces | Where-Object {-not $_.IAResult.IsCompleted})
        {
            Start-Sleep -Milliseconds 50
        }
            
        $Runspaces | ForEach-Object {
            $_.Instance.EndInvoke($_.IAResult)            
        }
    }

    end
    {
        $RunspacePool.Dispose()
    }
}
  • Related