0

I have a task where I need to compress all child directories (child is each day of a month) within each sub-parent directory (Month) and move to an archive folder. Then delete the originals. Also an option to perform this action on folders last modified 3weeks ago.

Example

E:
  -Share1    (Static, does not change)
     -2019     (Kept for this year)
        - 01   (Month)
            -01 (1st day)
            -02 (second day)
            -03 (third day
            .............
            -31  (31st day of the month, where applicable)

   -02 (second Month)
      -01 (1st day)
      -02 (second day)
      -03 (third day
      .............
      -31  (31st day of the month, where applicable)


  -Share~12....
     -2019
        - 01   (Month)
            -01 (1st day)
            -02 (second day)
            -03 (third day
             .............
            -31  (31st day of the month, where applicable)

        -02 (second Month)
            -01 (1st day)
            -02 (second day)
            -03 (third day
            .............
            -31  (31st day of the month, where applicable)

(12 static parent folders / shares) I need the script to go down through each parent folder to a depth of 3 (the day) and compress the 01 - 31 folders (days of the month) to an archive folder and keep the folder structure the same. Then on successful compression, delete the day folders that was just compressed.

I have very little experience of Powershell scripting but have searched many resources and taken bits from others and put them together. What I have currently is a script that compresses a specified child directory (first day of the month) and moves them to the 'archive' directory, and also delete the original.

What I dont have is the capability to get the script to go on to the 2nd -> 31st and do the same.

if (-not (test-path "$env:ProgramFiles\7-Zip\7z.exe")) {throw "$env:ProgramFiles\7-Zip\7z.exe needed"} 
set-alias sz "$env:ProgramFiles\7-Zip\7z.exe"

$files="E:\Live_data\2019\01"
$target="E:\Archived_data\2019\01"

$dirs = Get-ChildItem -Path $files | Where-Object { $_.Attributes -eq "Directory" }

# Creates 7z files based on the parent folders name and drops it inside the archive folder
Foreach ($dir in $dirs)
{
      $name = $dir.name
      $newname = $name.ToLower() -replace(" ","")
      sz a -t7z "$target\$newname" "$files\$dir"

}

# Once archive created delete folder
if(Test-Path $target) {
    Remove-Item -Path $files -Force -Recurse -Confirm:$false
    Write-Host "directory removed: $files"
}

I'd greatly appreciate any help that I can get with this.

8
  • What value do you get for $dirs.count? – Keith Miller Apr 27 '19 at 21:18
  • sz a -t7z "$target\$newname" "$files\$dir" Should be sz a -t7z "$target\$newname" "$files\$name" – Keith Miller Apr 27 '19 at 21:35
  • @KeithMiller Sorry, I dont quite get what you mean. Running $dirs.count, I get 0. The example I placed above in the question, isnt the real data that I will be working on. – user1028580 Apr 27 '19 at 22:02
  • @KeithMiller Thanks for that. I amended the script and re-ran it. I do not see any difference in the output. Same as before. Can you explain what it is supposed to do? Thanks & Rgrds. – user1028580 Apr 27 '19 at 22:10
  • The idea is to verify you have a collection of directory objects after the get-childitem. Because it looked like your loop structure was correct, And it is. But your creation of the source string ("$files\$dir")is wrong. $dir is an object, not a string. – Keith Miller Apr 27 '19 at 22:11
1

Something like this should work:

$files  = "E:\Live_data\2019"
$target = "E:\Archived_data\2019"

Get-ChildItem -Path "$files\*\*" -Directory |
   Foreach-Object {
      $month   = $_.Parent.Name
      $newname = $_.name.ToLower() -replace(" ","")
      sz a -t7z "$target\$month\$newname" $_.FullName
      if(Test-Path "$target\$month\$newname") {
         Remove-Item -Path $_.FullName -Force -Recurse -Confirm:$false
      }
      If (!(Get-ChildItem -path $_.Parent.FullName -Directory)) { # all sub-folders archived
         Remove-Item -Path $_.Parent.FullName -Force
         Write-Host ("directory removed: {0}" -f $_.Parent.FullName)
      } 
   }

Keith

5
  • Thanks for that. I ran the above and I think that its nearly there. Two issues that I can see. (I've tried to tweak but no progress...) 1) When I run it, it compress the first 1day and move it to archive but then tells me that it cannot delete the entire month as there are other days in there. Fair enough. I can select the option to select NO and then the script will proceed to process 02 (click no again) and it will go to 03 and so on and so on. I have 10 days in the month. If I select NO enough, it will proceed to the second month and 1st day - then repeat. – user1028580 Apr 28 '19 at 14:38
  • continuted... Doing this leaves the originals in place and also a compressed exact copy copy in Archive. – user1028580 Apr 28 '19 at 14:39
  • If I were to select Y, then it will delete days 02 - 10. Then move on to 2nd month, compress 01 day and ask again do I want to delete. If I do, then it deletes all 02-10 days of 2nd month. – user1028580 Apr 28 '19 at 14:40
  • imgur.com/rX70Qmg – user1028580 Apr 28 '19 at 14:48
  • Corrected If statement to: If (!(Get-ChildItem -path $_.Parent.FullName -Directory)) – Keith Miller Apr 28 '19 at 15:51
0

My answer builds on @KeithMiller's.

It extends the idea of multiple directory levels in the Get-ChildItem by specifying a range instead of a wildcard, restricting subfolders to month/day numbers

Also the removing of files is only done when the previous 7z was succesful.

Tested with a copy of my Q:\Test\2019\MM\dd folder with the same structure.

## Q:\Test\2019\04\28\SO_1430440.ps1

if (!(Test-Path "$ENV:ProgramFiles\7-Zip\7z.exe")) {
    throw "$ENV:ProgramFiles\7-Zip\7z.exe needed"
}
Set-Alias sz "$env:ProgramFiles\7-Zip\7z.exe"

$files  =     "E:\Live_data\2019"
$target = "E:\Archived_data\2019"

Get-ChildItem -Path "$files\[01][0-9]\[0-3][0-9]" -Directory |
# Where {$_.LastWriteTime.Date -gt [Datetime]::Today.AddDays(-21)}|
  Foreach-Object {
    $month = $_.Parent.Name
    $day   = $_.Name

    If(!(Test-Path "$target\$month")){MD "$target\$month" | Out-Null}

    sz a -t7z "$target\$month\$day" $_.FullName
    $output = (sz a -t7z "$target\$month\$day" $_.FullName 2>&1)
    if ($LastExitCode -ne 0){
        "ERROR executing: sz a -t7z `"$target\$month\$day`" $_.FullName"
        $output
        pause
        return
    } else { #remove day folder
        Remove-Item -Path $_.FullName -Force -Recurse -Confirm:$false
    }
}

A Where-Object to restrict to folders with a LastWriteTime greater 21 days is included, but commented out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.