Search code examples
powershelldirectoryget-childitemcompress-archive

Archiving files according to date in file name. Powershell script


I am trying to make simple powershell script that is archiving files coming in daily. Every file has date at the beggining of its name, for example: 20211220_Something.csv, 20211220_SomethingElse.txt, 20211219_Something.csv, 20211219_SomethingElse.txt etc...

I would like to make script that collects all files with extensions (*.txt, *.csv, *.xslx) from specifict directories which are:

\\Main\Files and \\Main\Files\SecondaryFiles

and archives all files with above extensions to for example \\Main\Files\archive\2021\12\20.12.zip

where 2021, 12 and 20.12 are elements of date provided in file name prefix. Inside 20.12.zip we have all files from \\Main\Files with directory named "SecondaryFiles" in which theres all files from the \\Main\Files\SecondaryFiles. After archiving i would like to delete all the files that i just zipped.

Right now i have this piece of code which loop through all files in the \Main\ dir and extracts date prefix. I have tried using [Datetime]::parseexact() method but it doesnt work since my loop returns whole path. Anybody has any idea how to approach this?

$Date = Get-Date
$Day = $Date.Day
$Month = Date.Month
$Year = $Date.Year
$directoryPath = "\\Main\Files\archive'"+$Year+"\"+$Month
$files = Get-ChildItem -Path "\\Main\Files" -Include *.txt, *.csv, *.xlsx -Recurse
for ($i=0; $i -lt $files.Count; $i++){
$temp = $files[$i].FullName.split("_")[1]
}

if(!Test-Path -path $directoryPath){
    New-Item -ItemType directory -Path $directoryPath
}

Compress-Archive -Path "\\Main\Files", "\\Main\Files\*.txt", "\\Main\Files\*.csv", "\\Main\Files\*.xlsx", "\\Main\Files\SecondaryFiles\*.txt", "\\Main\Files\SecondaryFiles\*.csv", "\\Main\Files\SecondaryFiles\*.xlsx" -Update -DestinationPath "\\Main\Files\archive\$Year\$Month\$Day.$Month.zip"

Then i am removing items from the original directory.

Also one thing worth mentioning is that I cant be sure if folder contains only files from todays date. So script should work fine when theres files from like all week lets say 20211214 till 20211220.

So again i would like to Compress-Archive files like i did above but instead todays date the path would contain extracted date from file name prefix.


Solution

  • Use Group-Object to group all files having the same date prefix together and use that to create the output subdirectories, the final .zip file and also to remove the original files after zipping.

    $sourcePath  = '\\Main\Files'
    $destination = '\\Main\Files\archive'
    
    Get-ChildItem -Path $sourcePath -Include '*.txt', '*.csv', '*.xlsx' -Recurse |
    # select only files that start with 8 digits followed by an underscore
    Where-Object { $_.BaseName -match '^\d{8}_' } |
    # group the files on the date part and loop trhough these groups
    Group-Object { $_.BaseName.Substring(0,8) } | ForEach-Object {
        # split the date part into variables. Automatic variable $_ represents one Group, 
        # so we can take that group's Name to split into date parts 
        $year, $month, $day = $_.Name -split '(\d{4})(\d{2})(\d{2})' -ne ''
        # construct the target folder path for the zip file
        $targetPath = Join-Path -Path $destination -ChildPath ('{0}\{1}' -f $year, $month)
        # create the new sub directory if it does not yet exist
        $null = New-Item -Path $targetPath -ItemType Directory -Force
        # create the full path and filename for the zip file
        $zip = Join-Path -Path $targetPath -ChildPath ('{0}.{1}.zip' -f $day, $month)
        # compress the files in the group  
        Compress-Archive -Path $_.Group.FullName -DestinationPath $zip -Update
    
        # here is where you can delete the original files after zipping
        $_.Group | Remove-Item -WhatIf
    }
    

    Note I have added switch -WhatIf to the Remove-Item cmdlet. This is a safety switch, so you are not actually deleting anything yet. The cmdlet now only displays what would be deleted. Once you are happy with this output, remove that -WhatIf switch so the files are deleted.