-1

I am currently strugling on a simple powershell script to archive files.

I have thousand of old file in a folder and i want to archive them depending on the month/year of their creation date in archives named "YYYYMM".

I use the code below

Get-ChildItem -Path $sourcePath -filter $filter  |
Where-Object {(($_.CreationTime) -le $dateCriteria) -and ($_.psIsContainer -eq $false)}|
ForEach {
    $archive = "{0:yyyy}{0:MM}.7z" -f $_.CreationTime
    $archivePath= Join-Path -Path $destinationFolder -ChildPath $archive
    & "C:\Program Files\7-Zip\7z.exe" a -mx9 -t7z -m0=lzma2 -sdel $archivePath$_.FullName  |Out-Null
}

The logic seems fine as it creates files like 201809.7z 201810.7z ... In my destination folder.

The problem is i see errors in the console:

System ERROR:
The file exists

or

System ERROR:
Access denied

or

System ERROR:
The file exists
ERROR: ********\202011.7z
Can not open the file as archive

As a result, in my destination folder, in addition to the expected archive files i have file like "201810.7z.tmp1"

I changes the working directory to isolate those files by adding -w"{WORK_PATH}" to the command line.

I also added Start-Sleep -Milliseconds 1 as it looked like concurrent access even if my script is mono threaded (maybe 7zip doesn't end properly) but it didn't work.

With Start-Sleep -Milliseconds 500it seems to work but for obvious reasons i dont want to use that. What would the proper way to do that be ?

EDIT 1 Following MisterSmith's answer i changed my code for

Get-ChildItem -Path $emplacementSource -filter $filtreNomFichiers  |
Where-Object {(($_.CreationTime) -le $dernierJour) -and ($_.psIsContainer -eq $false)}|
ForEach {
    $archive = "{0:yyyy}{0:MM}.7z" -f $_.CreationTime
    $cheminArchive= Join-Path -Path $dossierCible -ChildPath $archive
    [Array]$arguments = "a" ,"-w$workDir", "-mx9" ,"-t7z" ,"-m0=lzma2" ,"-sdel" ,$cheminArchive, $_.FullName    
    
    $pinfo = New-Object System.Diagnostics.ProcessStartInfo
    $pinfo.FileName = $sevenZip
    $pinfo.RedirectStandardError = $true
    $pinfo.CreateNoWindow= $true
    $pinfo.UseShellExecute = $false
    $pinfo.Arguments = "$arguments"
    
    $process = New-Object System.Diagnostics.Process
    $process.StartInfo = $pinfo
    $process.Start() 
    
    $output = $process.StandardError.ReadToEnd()
    
    $process.WaitForExit()
                        
    if(0 -ne $process.ExitCode){                                                
        Write-Output "$(Get-TimeStamp) Erreur: $output"  | Out-file $fichierLogs -append
    }
}   

I still have File exists errors and .tmpX archives in my temp folder.

Erwan C.
  • 709
  • 5
  • 18

1 Answers1

1

Instead of using & use Start-Process and pass the -wait switch or use -PassThru switch and the returned System.Diagnostics.Process to check if the process has finished yourself. Either will get the same result as your Start-Sleep -Milliseconds 500 test, but it will only wait for the time taken by 7z.exe to complete its execution.


Side note - you can append multiple files at once. That would probably work out quicker overall than adding each file separately.

MisterSmith
  • 2,884
  • 1
  • 10
  • 13