Keep x versions of a file in Folder - delete rest - powershell

I have backup process that makes a copy of files and appending system time at the end. Date stamp indicates when the file was received via FTP (ddMMYYYYhhmmss).
fileName1.ZIP02062015090653
fileName1.ZIP01062015090653
fileName1.ZIP31052015090653
fileName1.ZIP29052015090653
fileName1.ZIP28052015090653
fileName1.ZIP21052015090653
fileName2.ZIP02062015090653
fileName3.ZIP02062015090653
reportName1.PDF02062015090653
reportNameX.TXT02062015090653
etc..
I need the script to keep the 5 most recent versions of each file.
i.e. fileName1.ZIP21052015090653 <- this should get deleted.
I was trying to work of a script below but it deletes everything after 5th file..
gci C:\temp\ -Recurse| where{-not $_.PsIsContainer}| sort CreationTime -desc|
select -Skip 5| Remove-Item -Force
I don't mind if script uses fileName, dateModified, creationTime or DateStamp - I'd like to be able to keep 5 versions of each file and blow away oldest one.

Try this:
gci C:\temp\ -Recurse |
where{-not $_.PsIsContainer} |
Group-Object basename |
foreach {
$_.Group |
sort CreationTime -Descending |
Select -Skip 5 |
foreach { Remove-Item $_.fullname -Force -WhatIf }
}
That will group the files by the basename, then sort/delete within each group.
Remove the -Whatif if the results look right and re-run to actually delete the files.

Related

Powershell - Selective moving files into subfolder (keeping the newest of each FIRST13 letter grouping)

extreme powershell newbie here so please be gentle...
I have a filing system where where files in folders are generated semi-automatically, with multiple versions being kept as redundancy (we really do revert regularly).
Files within the folder are named with the first 13 characters as the identifier, with various dates or initials afterwards.
12345-A-01-01_XYZ_20191026.pdf
i.e. the file is 12345-A-01-01 and everything past the first 13 characters is "unpredictable"
FILE000000001xxxxxxx.pdf
FILE000000001yyyy.pdf
FILE000000001zzzzzz.pdf
FILE000000002xxxx.pdf
FILE000000002yyy.pdf
FILE000000002zz.pdf
FILE000000003xx.pdf
FILE000000003yyy.pdf
FILE000000003zzzz.pdf
I'm trying to write a script that can determine the newest version (by date modified file property) of each file "group"
i.e. the newest FILE000000001*.pdf etc
and slide all the others into the .\Superseded subfolder
All I've managed to get so far is a "list" sorting to show the newest at the top of "each" group... now I need to know how to keep that file, and move the others... any direction or help would be great thanks :)....
$_SourcePath = "C:\testfiles"
$_DestinationPath = "C:\testfiles\Superseded"
Get-ChildItem $_SourcePath |
Where-Object {-not $_.PSIsContainer} |
Group-Object { $_.Basename.Substring(0,12) } |
foreach {
$_.Group |
sort LastWriteTime -Descending
} | Move-Item -Destination $_DestinationPath
I think you are pretty close. Since you sorted descending order you should just skip the first file:
$SourcePath = "C:\testfiles"
$DestinationPath = "C:\testfiles\Superseded"
Get-ChildItem $SourcePath -File |
Group-Object { $_.Basename.Substring(0,12) } |
ForEach-Object {
$_.Group |
Sort-Object LastWriteTime -Descending |
Select-Object -skip 1 |
Move-Item -Destination $DestinationPath -WhatIf
# Note: Above, the move has to be in each iteration of the loop
# so we skip the first (newest) of each file.
}
You don't need Where-Object {-not $_.PSIsContainer} , use the -File Parameter instead.
Also I wouldn't name your variables $_***. That's bound to get confused with $_ like the pipeline variable.
I added -WhatIf to the move command so you can test without causing any damage ...
I didn't test it, but it looks about right.

Powershell Delete all files apart from the latest file per day

I have a folder that contains a lot of files, multiple files per day.
I would like to script something that deletes all but the latest file per day.
I have seen a lot of scripts that delete files over X days old but this is slightly different and having written no powershell before yesterday (I'm exclusively tsql), I'm not really sure how to go about it.
I'm not asking anyone to write the code for me but maybe describe the methods of achieving this would be good and I can go off an research how to put it into practise.
All files are in a single directory, no subfolders. there are files I dont want to delete, the files i want to delete have file name in format constant_filename_prefix_YYYYMMDDHHMMSS.zip
Is powershell the right tool? Should i instead be looking at Python (which I also don't know) Powershell is more convinient since other code we have is written in PS.
PowerShell has easy to use cmdlets for this kind of thing.
The question to me is if you want the use the dates in the file names, or the actual LastWriteTime dates of the files themselves (as shown in File Explorer).
Below two ways of handling this. I've put in a lot of code comments to help you get the picture.
If you want to remove the files based on their actual last write times:
$sourceFolder = 'D:\test' # put the path to the folder where your files are here
$filePrefix = 'constant_filename_prefix'
Get-ChildItem -Path $sourceFolder -Filter "$filePrefix*.zip" -File | # get files that start with the prefix and have the extension '.zip'
Where-Object { $_.BaseName -match '_\d{14}$' } | # that end with an underscore followed by 14 digits
Sort-Object -Property LastWriteTime -Descending | # sort on the LastWriteTime property
Select-Object -Skip 1 | # select them all except for the first (most recent) one
Remove-Item -Force -WhatIf # delete these files
OR
If you want to remove the files based the dates in the file names.
Because the date formats you used are sortable, you can safely sort on the last 14 digits of the file BaseName:
$sourceFolder = 'D:\test'
$filePrefix = 'constant_filename_prefix'
Get-ChildItem -Path $sourceFolder -Filter "$filePrefix*.zip" -File | # get files that start with the prefix and have the extension '.zip'
Where-Object { $_.BaseName -match '_\d{14}$' } | # that end with an underscore followed by 14 digits
Sort-Object -Property #{Expression = {$_.BaseName.Substring(14)}} -Descending | # sort on the last 14 digits descending
Select-Object -Skip 1 | # select them all except for the first (most recent) one
Remove-Item -Force -WhatIf # delete these files
In both alternatives you will find there is a switch -WhatIf at the end of the Remove-Item cmdlet. Yhis is for testing the code and no files wil actually be deleted. Instead, with this switch, in the console it writes out what would happen.
Once you are satisfied with this output, you can remove or comment out the -WhatIf switch to have the code delete the files.
Update
As I now understand, there are multiple files for several days in that folder and you want to keep the newest file for each day, deleting the others.
In that case, we have to create 'day' groups of the files and withing every group sort by date and delete the old files.
This is where the Group-Object comes in.
Method 1) using the LastWriteTime property of the files
$sourceFolder = 'D:\test' # put the path to the folder where your files are here
$filePrefix = 'constant_filename_prefix'
Get-ChildItem -Path $sourceFolder -Filter "$filePrefix*.zip" -File | # get files that start with the prefix and have the extension '.zip'
Where-Object { $_.BaseName -match '_\d{14}$' } | # that end with an underscore followed by 14 digits
Group-Object -Property #{Expression = { $_.LastWriteTime.Date }} | # create groups based on the date part without time part
ForEach-Object {
$_.Group |
Sort-Object -Property LastWriteTime -Descending | # sort on the LastWriteTime property
Select-Object -Skip 1 | # select them all except for the first (most recent) one
Remove-Item -Force -WhatIf # delete these files
}
Method 2) using the date taken from the file names:
$sourceFolder = 'D:\test' # put the path to the folder where your files are here
$filePrefix = 'constant_filename_prefix'
Get-ChildItem -Path $sourceFolder -Filter "$filePrefix*.zip" -File | # get files that start with the prefix and have the extension '.zip'
Where-Object { $_.BaseName -match '_\d{14}$' } | # that end with an underscore followed by 14 digits
Group-Object -Property #{Expression = { ($_.BaseName -split '_')[-1].Substring(0,8)}} | # create groups based on the date part without time part
ForEach-Object {
$_.Group |
Sort-Object -Property #{Expression = {$_.BaseName.Substring(14)}} -Descending | # sort on the last 14 digits descending
Select-Object -Skip 1 | # select them all except for the first (most recent) one
Remove-Item -Force -WhatIf # delete these files
}

To make a copy of the file in the same folder with only date change - using powershell

I have a report which needs to be sent out daily. Every morning, I manually using
Ctrl + C and make a copy of the report in a specific folder, then open the excel file and refresh the contents.
To remove this everyday manual labor, I wrote a power shell script which could automate the task for me.
Script:
$OriginalDir = "C:\Users\101335\Google Drive\BI\Aditya\Daily Order Report"
$BackupDir = "C:\Users\101335\Desktop\Test"
$LatestFile = Get-ChildItem -Path $Originaldir | Sort-Object LastAccessTime -Descending |
Select-Object -First 1
Copy-Item -path "$OriginalDir\$LatestFile" "$BackupDir\$LatestFile"
Get-ChildItem -Path $BackupDir | Rename-Item -newname {"Daily Order Report _India_" +$_.CreationTime.toString("dd.MM.yyyy") + ".xlsx"}
$LatestFile1 = Get-ChildItem -Path $BackupDir | Sort-Object LastAccessTime -Descending |
Select-Object -First 1
Copy-Item "C:\Users\101335\Desktop\Test\*.*" "C:\Users\101335\Google Drive\BI\Aditya\Daily Order Report"
Start-Sleep -s 2
Get-ChildItem -Path $BackupDir -Include * | remove-Item -recurse
Problem:
What I have tried to do is:
copy the latest file from the Original folder
copy it up to the backup folder
rename it
copy it back again to the original folder
delete the file from the backup folder.
I have been able to pursue the steps up to renaming of the file with the current date, but I am not able to copy it back to the original folder.
Can somebody help me out with this?
If you're copying to a backup directory, renaming, copying back to original and then deleting from the backup directory, I don't know why you need to use a backup directory at all - You could just copy the file into the original directory with the new name.
Try:
$OriginalDir = "C:\Users\101335\Google Drive\BI\Aditya\Daily Order Report"
$LatestFile = Get-ChildItem -Path $Originaldir | Sort-Object LastAccessTime -Descending | Select-Object -First 1
$LatestFileName = $LatestFile.Name
$LatestFileTime = $LatestFile.CreationTime.toString("dd.MM.yyyy")
Copy-Item "$OriginalDir\$LatestFileName" $("{0}\Daily Order Report _India_{1}.xlsx" -f $OriginalDir, $LatestFileTime)

Outputing Remove-Item to a log file

Scanning a directory for a specific set of files and sorting them by date. Keeping 7 of the LATEST copies of the file regardless of date, and removing the oldest if over 7. I am having a hard time producing a log file showing the deletes since Remove-Item has no output.
Below is a copy of my code:
$path = "C:\- Deploy to Production -\Previous Deploys\*_*_BOAWeb.rar" #BOA
$files = Get-ChildItem -Path $path -Recurse | Where-Object {-not $_.PsIsContainer}
$keep = 7
if ($files.Count -gt $keep) {
$files | Sort-Object CreationTime |
Select-Object -First ($files.Count - $keep) |
Remove-Item -Force
}
First off you are over complicating things. Add -Descending to your Sort command, and then change your Select to -Skip $keep. It's simpler that way. Then you have options for outputting your deleted files.
Remove-Item -Force -Verbose 4>&1 | Add-Content C:\Path\To\DeletedFiles.log
or (keeping with your current code above)
Select-Object -First ($files.Count - $keep) |Tee-Object -filepath C:\Path\To\DeletedFiles.log -append
The first will output the verbose output of Delete-Item and append it to whatever log file you specify the path for (use Set-Content if you want to replace the log instead). The second option will append the [FileInfo] objects onto a log that you specify.
Edit: As pointed out by Ansgar Wiechers, I had forgotten to to combine my verbose and stdout streams, so 4>&1 was added to the above code to correct that issue.

Powershell Script to get files from last year folder

I have situation where I have 3000 vendors in folder structure. Each vendor then has folders for each year (2001, .... 2014) and other folders as well. Is there a way to list all the files that is in latest year (whichever year).
Basically, I need to upload all the latest agreement files from file-share to SharePoint.
One Liner
Get-ChildItem | %{ $_.FullName | Get-ChildItem [1-9][0-9][0-9][0-9] | sort -Descending | Select-Object -First 1 | Get-ChildItem }
You start from the root folder, for each folder you get all the folders which name looks like a year, sort them, take the first one, and get all it's folders.
Of course, there is a plenty of issues with this. e.g. there has to be at least one year folder, no 'year' files etc. I will leave you tackle that kind of problems.
First I would recursively iterate through all the directories, matching the ones that are equivalent to the current year:
$thisYearDirs = get-childitem -Directory -Recurse | where {$_.Name -eq (get-date).year}
then you would just get the files in each of those:
$thisYearDirs | get-childitem
You could also do it all in one line:
get-childitem -Directory -Recurse | where {$_.Name -eq (get-date).year} | get-childitem
Note that the -directory switch needs powershell v3, you could filter out directories in earlier versions by modifying the where clause condition to do it:
get-childitem -Recurse | where {$_.PSIsCOntainer -and $_.Name -eq (get-date).year} | get-childitem