[CmdletBinding(SupportsShouldProcess)]param( [string]$SourcePath=".", [string]$SourceSet="*.rar", [switch]$Recurse, # The extension of the output zip file, don't forget to include the dot, default is ".zip" [string]$ZipExtension=".zip", [string]$ZipDestPath="./zipped", [string]$ZipOptions="-mm=Deflate -mfb=258 -mpass=15", [string]$MoveProcessedTo="done", [switch]$Flatten, [switch]$MuteSkipped, [switch]$Force, [ScriptBlock]$GetExtractCmd ) $local:Get7zExtractCmd = { param([string]$ArchivePath,[string]$TmpPath) $local:7zCmd = "7z " if( $Flatten ) { $7zCmd += "e " } else { $7zCmd += "x " } $7zCmd += "-o$(Get-ShellSafePath $TmpPath) $(Get-ShellSafePath $ArchivePath)" $7zCmd } $local:GetUnrarExtractCmd = { param([string]$ArchivePath,[string]$TmpPath) "unrar x $(Get-ShellSafePath $ArchivePath)" } if( -not $GetExtractCmd ) { $GetExtractCmd = $Get7zExtractCmd if( Get-Command unrar -ErrorAction Ignore ) { $GetExtractCmd = $GetUnrarExtractCmd } } function Get7zCompressCmd { param([string]$ArchivePath),[string]$CompressOptions $local:7zCmd = "7z a -sdel " if( -not $Flatten ) { $7zCmd += "-r " } $7zCmd += "$CompressOptions $(Get-ShellSafePath $ArchivePath)" $7zCmd } # Create a new temporary dir $local:DestPathRoot = Get-Path "$ZipDestPath/" $local:TempPath = Join-Path $DestPathRoot ([System.IO.Path]::GetRandomFileName()) $local:DonePath = [string]::Empty if( $MoveProcessedTo ) { $DonePath = Get-Path $MoveProcessedTo } $local:runTimeSpan = [System.Diagnostics.Stopwatch]::StartNew() $local:lastStatus = $runTimeSpan.Elapsed $SourcePath = Get-Path $SourcePath $local:srcSet = Get-ChildItem -Recurse:$Recurse -LiteralPath $SourcePath -Include $SourceSet $local:progress = [ordered]@{ Activity = "ConvertTo-Zip $SourcePath" ItemCount = $srcSet.Count ItemProgress = 0 Elapsed = $runTimeSpan.Elapsed } Write-Verbose "`n`tSourcePath: $SourcePath;`n`tTempPath: $TempPath;`n`tDestPathRoot: $DestPathRoot;`n`tDonePath: $DonePath" foreach( $local:srcFile in $srcSet ) { Write-Verbose "Processing $($srcFile.Name)..." $progress.ItemProgress++ $progress.Elapsed = $runTimeSpan.Elapsed if( ($runTimeSpan.Elapsed - $lastStatus).TotalSeconds -gt 3 ) { Show-Progress @progress -Status "Processing $($srcFile.Name)..." } if( Test-Path -LiteralPath $TempPath ) { Remove-Item -Recurse -Force -LiteralPath $TempPath -ErrorAction Stop } $null = New-Item -ItemType Directory -Force -Path $TempPath -ErrorAction Stop -WhatIf:$false $local:relPath = $srcFile.DirectoryName.Replace($SourcePath,[string]::Empty) $local:destPath = $srcFile.DirectoryName.Replace($SourcePath,$DestPathRoot) $local:destZipPath = $(Join-Path $destPath "$($srcFile.BaseName)$ZipExtension") # Write-Verbose "relPath = $relPath`ndestPath = $destPath`ndestZipPath = $destZipPath" $local:ActionStatus = "Failed" Write-Verbose "Dest: $destZipPath" if( -not $Force -and (Test-Path -LiteralPath $destZipPath) ) { Write-Verbose "Skipping, dest already exists: `"$($destZipPath.Replace($DestPathRoot,[string]::Empty))`"" $ActionStatus = "Skipped" } else { Push-Location -LiteralPath $TempPath -ErrorAction Stop $local:nextCmd = Invoke-Command $GetExtractCmd -ArgumentList @( $srcFile.FullName, $TempPath ) $null = Invoke-ExpressionEx $nextCmd if( -not (Get-ChildItem -Recurse -File -LiteralPath $TempPath).Length ) { Write-Warning "Failed to convert file:`n`t$($srcFile.FullName)" $ActionStatus = "Failed" } else { $local:destFile = Join-Path $destPath "$([System.io.path]::GetRandomFileName()).zip" $nextCmd = Get7zCompressCmd -ArchivePath $destFile $null = Invoke-ExpressionEx $nextCmd if( -not (Test-Path -LiteralPath $destPath ) ) { $null = New-Item -Type Directory -Path $destPath } $null = Move-Item -Force:$Force -LiteralPath $destFile $destZipPath $ActionStatus = "Processed" } Pop-Location } if( Test-Path -PathType Container -LiteralPath $TempPath ) { Remove-Item -Recurse -Force -LiteralPath $TempPath -WhatIf:$false } if( $DonePath ) { $local:doneFinalPath = Join-Path $DonePath $relPath if( -not (Test-Path -LiteralPath $doneFinalPath) ) { $null = New-Item -Type Directory $doneFinalPath } $local:moveParams = [ordered]@{ LiteralPath=$srcFile.FullName Destination=$doneFinalPath } if( Test-Path (Join-Path $doneFinalPath $($srcFile.Name))) { $moveParams.Confirm = $true $moveParams.Force = $true } Move-Item @moveParams } if( $ActionStatus -eq 'Skipped' -and $MuteSkipped ) { continue } [PSCustomObject]([ordered]@{ Action = $ActionStatus SrcMoved = $(if($DonePath){ $true } else {$false}) Path = $relPath File = $srcFile.BaseName }) }