i have probably searched the whole web, but I'm not able to help myself. Otherwise I'm just incapable.
All I want is to delete folders after 30 days and display the results in a simple .log file.
dir "C:\Users\sam\Desktop\Files_todelete\*" -ErrorAction SilentlyContinue | Where { ((Get-Date) - $_.LastWriteTime).days -gt 30 } | Remove-Item -Recurse
This works for me, but I tried nearly everything to log the results.
Hopefully you can help me to fix this issue.
You need to include logging part to your script. You can make foreach loop for every item that needs to be removed and write down activity to log file. Here is an example:
$LogFile = 'C:\log.txt'
dir "C:\Users\sam\Desktop\Files_todelete\*" -ErrorAction SilentlyContinue |
Where { ((Get-Date) - $_.LastWriteTime).days -gt 30 } |
ForEach-Object {
Remove-Item $_.FullName -Recurse
Out-File -InputObject $('Removed {0}' -f $_.FullName) -FilePath $LogFile -Append
}
So in this case it worked for me, but I want to use the Script for network drives. If I edit the path everything seems to be fine. But the problem here is the permission. Therefore I found a solution with Get-ChildItem -Directory.
My question here is can pipe this in front of the Remove-Item command?
Like:
$LogFile = '\netshare\folder\log.txt'
dir "\netshare\Files_todelete*" -ErrorAction SilentlyContinue |
Where { ((Get-Date) - $_.LastWriteTime).days -gt 30 } |
ForEach-Object {
Get-ChildItem -Directory | Remove-Item $_.FullName -Recurse
Out-File -InputObject $('Removed {0}' -f $_.FullName) -FilePath $LogFile -Append
}
Logically the Get-ChildItem needs to be in front of the loop?! But I'm not that firm to edit the beginning of the loop correctly.
Related
I am wondering if there is better way to make a script on PowerShell these instructions:
Search on 3 paths. Ex.
$LOGDIRS="C:\NETiKA\GED\Production\RI\log";"C:\NETiKA\GED\Test\RI\log";"C:\NETiKA\Tomcat-8.0.28\logs"
Find all files that are older than 7 days and copy on a file that I will call file.list . EX. > C:\Test\file.list
When I copied on my file.list, I need to search all the name of the files and delete them.
Apparently when you have more than thousands of file, this is the
fastest way to delete.
$LOGDIRS=C:/NETiKA/GED/Production/RI/log;C:/NETiKA/GED/Test/RI/log;C:/NETiKA/Tomcat-8.0.28/logs
$KEEP=-7
Get-ChildItem -Path $LOGDIRS -Recurse -Directory -Force -ErrorAction SilentlyContinue |
Select-Object FullName > files.list |
Foreach-Object {
if ($_.LastAccessTime -le (get-date).adddays($KEEP)) {
remove-item -recurse -force $_
}
};
Something like this should help you get started.
$path1 = "E:\Code\powershell\myPS\2018\Jun"
$path2 = "E:\Code\powershell\myPS\2018\Jun\compareTextFiles"
$path3 = "E:\Code\powershell\myPS\2018\May"
$allFiles = dir $path1, $path2, $path3 -File
$fileList = New-Item -type file file.list -Force
$keep = -7
$allFiles | foreach {
if ($_.LastAccessTime -le (Get-Date).AddDays($keep)) {
"$($_.FullName) is older than 7 days"
$_.FullName.ToString() | Out-File $fileList -Append
}
else {
"$($_.FullName) is new"
}
}
You can add deletion in the code in IF Block if you wish or check the file and do it later on. Your code has many issues which are very basic to PowerShell, e.g: once you use Select-Object the next pipeline will only receive the property you selected. You have tried using LastAccessTime in later pipe when you only selected to go ahead with FullName property.
Also, redirecting to a file and again using pipeline looks very messy.
Remove-Item accepts piped input and a
Where will filter the age
to first check what would be deleted I appended a -WhatIf to the Remove-Item
$LOGDIRS="C:\NETiKA\GED\Production\RI\log","C:\NETiKA\GED\Test\RI\log","C:\NETiKA\Tomcat-8.0.28\logs"
$KEEP=-7
Get-ChildItem -Path $LOGDIRS -Recurse -Directory -Force -ErrorAction SilentlyContinue |
Where-Object LastAccessTime -le ((get-date).AddDays($KEEP))
Remove-Item -Recurse -Force $_ -Whatif
I am new to PowerShell and I have created the following code to delete specific files and folders:
$myFolderPath = "C:\Test"
$myLimit = (Get-Date).AddDays(-14)
# Delete files according to filter.
Get-ChildItem -Path $myFolderPath -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $myLimit} | Remove-Item -Force
# Delete empty folders.
Get-ChildItem -Path $myFolderPath -Recurse -Force | Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } | Remove-Item -Force -Recurse
Is it possible to print out the full path of each item that will be removed to the console before the actual Remove-Item operation will be performed?
I guess sth. has to be added here....
... | Remove-Item -Force
and here...
... | Remove-Item -Force -Recurse
but I cannot find out how to implement that in an elegant way (without code duplication).
You can replace the remove-Item-Parts with
Foreach-Object { $_.fullname; Remove-Item -Path $_.Fullname (-Recurse) -Force}
LotPings comment might be better idea, if that is what you want.
It does not get a lot of attention but Tee-Object could be a simple addition to the pipeline here. Redirect the output to a variable that you can print later.
...Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $myLimit} |
Tee-Object -Variable removed | Remove-Item -Force
$removed | Write-Host
All of the file objects piped will be sent to $removed and then to Remove-Item. Since you have more than one delete pipeline you can also use the -Append parameter so that all files are saved in one variable if you so desired.
However this does not mean they were deleted. Just they made it passed the pipe. If you really wanted to be sure you should be using another utility like robocopy which has logging features.
Get-ChildItem –Path “H:\backups” –Recurse | Where-Object{$_.CreationTime –lt (Get-Date).AddDays(-4)} | Remove-Item
I have this Script that can delete files older than 4 days. However I want to control that it should delete X number of files+folder 4 days old and also want to get the logs so that I see it later.
Below is the script, Is it fine?
$Now = Get-Date
$Days = "4"
$TargetFolder = "H:\backups"
$LastWrite = $Now.AddDays(-$days)
$Files = get-childitem $TargetFolder -include *.* -recurse -force
Where {$_.CreationTime -le "$LastWrite"}
foreach ($i in Get-ChildItem $TargetFolder -recurse)
{
if ($i.CreationTime -lt ($(Get-Date).AddDays(-10)))
{
Remove-Item $Files -recurse -force
}
}
Write-Output $Files >> c:\delete.log
I believe this would work, allowing you to pass a path and a number of days you'd want to keep as parameters:
function RemoveOld($path, $filefilter, $daystokeep)
{
$findfiles = #(Get-ChildItem -Path $path -Include $filefilter)
$toRemove = $findfiles | Where-Object CreationTime -le (Get-Date).AddDays(-$daystokeep)
$toRemove >> c:\temp\delete.log
$toRemove | Remove-Item
}
RemoveOld -path "H:\backups\*" -filefilter "*" -daystokeep 4
May I also suggest, rather than deleting files older than a given time-frame, remove the files older than the most recent X number of files. In this way you'd always keep some number of files and not end up in a situation where all your files are deleted if the backup somehow fails to run for several days. It could be an option depending on how your folder structure is set up (modify the filefilter parameter so you don't delete more than desired).
function RemoveOlder($path, $filefilter, $filestokeep)
{
$findfiles = #(Get-ChildItem -Path $path -Include $filefilter)
if ($findfiles.Count -gt $filestokeep) {
$findfiles | Sort-Object LastWriteTime -Descending | Select-Object -Last ($findfiles.Count - $filestokeep) | Remove-Item
}
}
RemoveOlder -path "H:\backups\*" -filefilter "*" -filestokeep 4
On your original command, add this:
-Verbose 4>&1 | Out-File -FilePath D:\delete.log -Append
4 is Verbose output so this is redirecting Verbose to stdout 1, then redirecting both to a log file. The final command would be:
Get-ChildItem –Path “H:\backups” –Recurse `
| Where-Object{$_.CreationTime –lt (Get-Date).AddDays(-4)} `
| Remove-Item -Verbose 4>&1 | Out-File -FilePath C:\delete.log -Append
Update: If you want the command to run without interaction and continue on errors etc. for a scheduled task, add additional parameters to Remove-Item:
Get-ChildItem –Path “H:\backups” –Recurse `
| Where-Object{$_.CreationTime –lt (Get-Date).AddDays(-4)} `
| Remove-Item -Verbose -Force -ErrorAction SilentlyContinue -Confirm:$false 4>&1 `
| Out-File -FilePath C:\delete.log -Append
I'm trying to write a script that deletes all folders that are older than 60 days and create a logfile with the folder names in the directory where the folders have been deleted.
What I have now is:
Get-ChildItem -Directory -Path "\\share\dir1\dir2" |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-10) } |
Remove-Item -Force -Recurse | Out-File Auto_Clean.log -Append -WhatIf
The output stays like this for ages:
What if: Performing the operation "Output to File" on target "C:\users\bgijbels\Downloads\Auto_Clean.log".
When I remove the part for Out-File it works fine. It seems like the Out-File part is trying to write the name of every file in the folder to the log, while I only need to have the folder name. I think that's why it takes so long, if at all it gets past the part of creating the logfile. Any ideas? Thank you for your help.
You are getting a list of all files because -Recurse switch enumerates contents of folders so it can be deleted prior to the root folder removal. Try this:
Get-ChildItem -Directory -Path "\\share\dir1\dir2" |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-60) } | % {
$folder = $_;
Remove-Item $folder.FullName -Force -Recurse | Out-Null
$folder.FullName } |
Out-File Auto_Clean.log -Append -WhatIf
Directory object is kept as $folder var and you effectively echo its full path after deletion. Obviously take -WhatIf off the end after you are happy with results.
I have a script right now that looks for all files certain day old and certain file extension and it deletes all of the files. This works fine and it counts fine
Then I have to delete all folders that correspond to being empty and that includes all sub folders too.
I also have to output this into a file and display each file deleted. The output would show 30 folders deleted but actually 48 were really deleted.
Now my question is i am trying to do a count of all the folders deleted. I have this script but it just counts the deepest folders not all the ones deleted.
Here is the part of the script i can not get to count
$TargetFolder = "C:\Users\user\Desktop\temp"
$LogFile = "C:\Summary.txt"
$Count = 0
Date | Out-File -filepath $LogFile
get-childitem $TargetFolder -recurse -force | Where-Object {$_.psIsContainer}| sort fullName -des |
Where-Object {!(get-childitem $_.fullName -force)} | ForEach-Object{$Count++; $_.fullName} | remove-item -whatif | Out-File -filepath $LogFile -append
$Count = "Total Folders = " + $Count
$Count | Out-File -filepath $LogFile -append
Although the sort call will correctly send each directory through the pipeline in nesting order, since they are not really being removed (remove-item -whatif), the parents will still contain their empty child directories and so will not pass the second condition (!(get-childitem $_.fullName -force)). Also note that Remove-Item does not produce any output, so the deleted directories will not appear in the log.
Adapting Keith Hill's answer to a similar question, here is a modified version of the original script that uses a filter to retrieve all empty directories first, then removes and logs each one:
filter Where-Empty {
$children = #($_ |
Get-ChildItem -Recurse -Force |
Where-Object { -not $_.PSIsContainer })
if( $_.PSIsContainer -and $children.Length -eq 0 ) {
$_
}
}
$emptyDirectories = #(
Get-ChildItem $TargetFolder -Recurse -Force |
Where-Empty |
Sort-Object -Property FullName -Descending)
$emptyDirectories | ForEach-Object {
$_ | Remove-Item -WhatIf -Recurse
$_.FullName | Out-File -FilePath $LogFile -Append
}
$Count = $emptyDirectories.Count
"Total Folders = $Count" | Out-File -FilePath $LogFile -Append
Note that -Recurse was added to the call to Remove-Item, as empty child directories will remain when using -WhatIf. Neither flag should be needed when performing an actual remove on an empty directory.
Not tested:
get-childitem $TargetFolder -recurse -force |
where-object{$_.psiscontainer -and -not (get-childitem $_.fullname -recurse -force | where-object {!($_.psiscontainer)}}|
sort fullName -des |
Where-Object {!(get-childitem $.fullName -force)} |
ForEach-Object{$Count++; $_.fullName} |
remove-item -whatif |
Out-File -filepath $LogFile -append