Outputing Remove-Item to a log file - powershell

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.

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 - include Get-Date in .log file inside the Add-Content Cmdlet

I've made a small Powershell Script which deletes alle files and folders except specific ones.
The script itself works pretty good but I have a lot of troubble getting the logging to work. I'm currently on a good way with the Add-Content Cmdlet which works good. The only thing I now want to include is a small Get-Date Cmdlet inside the Add-Content which also includes the current time in the log when the specific file/folder was deleted. But I just can't get it to work properly. Can someone help me?
Here is what I got so far:
Get-ChildItem -Path 'C:\sample\*\notesdata' -Recurse -exclude names.nsf |
Select -ExpandProperty FullName |
Where {$_ -notlike 'C:\sample\*\notesdata\Roaming*'} |
Where {$_ -notlike 'C:\sample\*\notesdata\Archive*'} |
sort length -Descending |
Remove-Item -force -Recurse -Verbose 4>&1 | Add-Content -Path .\ergebnis.log, .\ergebnis2.log -Value (Get-Date)
The file "names.nsf" and the folders "Roaming", "Archive" will not get deleted.
Thanks for your help :)
Agree with #Olaf I'm guessing you're getting error like:
Add-Content : The input object cannot be bound to any parameters for
the command either because the command does not take pipeline input or
the input and its properties do not match any of the parameters that
take pipeline input.
If you want to date the output for logging purposes you could add something a ForEach-Object before the Add-Content command. Something like:
Remove-Item C:\temp\something.txt -Verbose 4>&1 | ForEach-Object{ "$(Get-Date -format g) : $($_)" } | Add-Content C:\temp\something2.txt
Let us know if that helps. Thanks.

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
}

Keep x versions of a file in Folder - delete rest

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.

Powershell - Delete folders containing a file with a specific FileDescription?

I am using the below code to get the FileDescription of a file:
(dir C:\test.exe).VersionInfo | select-object FileDescription | fl
This is working fine, the next step is: I am looking to search for all files that end with a specific FileDescription, then delete the folders where these files reside. Is this possible? Thanks!
There was an error in my pipe. The file information was lost since we only pipe .VersionInfo
Get-ChildItem C:\test.exe | Where-Object{$_.VersionInfo.FileDescription -like "*endofdescription"} | Remove-Item -WhatIf
It would make more sense if you were to use -Recurse to return more file and keep using Where-Object to filter just the ones you want. This should find the files and return their folder names. Since there could be more than one file in a folder that matches we could pipe the results in Select-Object -Unique to get the individual folders.
Get-ChildItem C:\MyFolder -Recurse | Where-Object{$_.VersionInfo.FileDescription -like "*endofdescription"} | ForEach-Object{Split-Path $_.FullName -Parent} | Select-Object -Unique | ForEach-Object{Remove-Item $_ -WhatIf -Confirm:$false -Force -Recurse}
I leave the -WhatIf as a precaution. Remove if the code suits your needs.
Does this work?
Get-ChildItem C:\MyFolder -Recurse | `
Where-Object{$_.VersionInfo.FileDescription -like "*endofdescription"} |`
%{$_.DirectoryName}|`
sort-object -unique| `
remove-item -recurse -whatif