Powershell script deleting files despite -Exclude switch - powershell

I have the following script where I'm trying to delete all the SQL .bak files except for the last two. When I run it it wipes out everything in the folder. Does -Exclude not work with array values?
$excludefile=get-childitem D:\TempDB | sort lastwritetime | select-object -Last 2 | select-object -Property Name | select-object -expandproperty Name
foreach ($element in $excludefile)
{
$element
remove-item -Path D:\TempDB -Exclude ($element) -Force
}

Is this what you're looking for?
Get-ChildItem D:\TempDB |
Sort-Object LastWriteTime -Descending |
Select-Object -Skip 2 |
Remove-Item -WhatIf
Of course, you can remove -WhatIf if this is what you need.

Related

Find the last modified files with different file names in PowerShell

I have a folder full of SQL backups from different DBs. I need to isolate the last modified from each DB and delete the rest.
I can find the last modified of them all and delete the rest but that would delete the last backup from the other 2 DBs.
$files = Get-ChildItem -Path $path -Recurse |
Where-Object {-not $_.PsIsContainer}
$keep = 1
if ($files.Count -gt $keep) {
$files | Sort-Object CreationTime |
Select-Object -First ($files.Count - $keep) |
Remove-Item -Force
}
This will just Keep the newest and remove the rest.
So if I have
db1.bak
db1.bak
db1.bak
db2.bak
db2.bak
db2.bak
db3.bak
db3.bak
db3.bak
how do I keep the last modified of each then delete the rest?
Group the files by name, skip the most recent file from each group, and remove the rest.
Get-ChildItem -Path $path -Recurse |
Where-Object {-not $_.PsIsContainer}
Group-Object Name |
ForEach-Object {
$_.Group |
Sort-Object LastWriteTime -Desc |
Select-Object -Skip 1 |
Remove-Item -Force
}

Powershell Copy Last Modified File

I'm trying to copy some files from a source to a destination, however the source has multiple folders and in the folders I'd like to copy just the last file.
I can isolate the last file with the folowing:
gci 'D:\Data' | sort LastWriteTime | select -last 1 -recurse
It only selects the last file in the folder, so I thought a loop would do it, such as:
$file = gci 'D:\Data' foreach ($files in $file) { sort LastWriteTime | select -last 1 | Copy-Item C:\Test\data}
However this keeps failing
Can someone point me in the right direction.
Get-ChildItem D:\Data -Directory | ForEach-Object {
Get-ChildItem $_.FullName -File -Recurse |
Sort-Object -Property LastWriteTime |
Select-Object -Last 1 |
Copy-Item -Destination C:\Test\data
}

How to get the directory location for file recently modified

Suppose we have two directories C:\username\test1 & C:\username\test2. Both directories contain same file script.ps1. Now with powershell script I want to search the file script.ps1 in both directories & want the complete file location of file which is latest modified/created.
I was using below command but it did not give the desired output
Get-ChildItem -Path "C:\username" script.ps1 -Recurse | Where-object {!$_.psIsContainer -eq $true} | ForEach-Object -Process {$_.FullName} | select -last 1
For a given directory you can use
Get-ChildItem C:\dir1\dir2 -Recurse -ErrorAction SilentlyContinue | Where {!$_.PsIsContainer}|select Name,DirctoryName, LastWriteTime |Sort LastWriteTime -descending | select -first 1   Name DirctoryName LastWriteTime
And if you want it to run for multiple directories, you will have to run a loop on each directory:
Get-ChildItem C:\dir\* | Where {$_.PsIsContainer} | foreach-object { Get-ChildItem $_ -Recurse -ErrorAction Sile   ntlyContinue | Where {!$_.PsIsContainer} | Select Name,DirectoryName, LastWriteTime, Mode | Sort LastWriteTime -descend   ing | select -first 1}
It will list files which are last modified for each directories.
Edit: Search for a file
You can use following command to search for a file recursively if it is there in multiple directories:
Get-ChildItem -Path C:\Myfolder -Filter file.whatever -Recurse -ErrorAction SilentlyContinue -Force
This will list all versions of the file found, from newest to oldest:
Get-ChildItem -Path "C:\UserName" `
-File `
-Recurse `
-Include "Script.ps1" |
Sort-Object LastWriteTime -Descending |
Format-Table LastWriteTime, FullName -AutoSize
If you only want the most recent one, then replace the Format-Table line with:
Select-Object -First 1

Remove-Item cmdlet causes "Cannot find path" while process of removal of .exe files in local folder

I have script that selects .exe files with the specified name from the local folder and removes all files, except first.
$P variable is defined in param.
$P ="$($env:USERPROFILE)\Desktop\I"
Then I got this error
$C = Get-ChildItem $P -Filter *.exe| Where-Object Name -Like '*r_2-2*' | Sort-Object Name -Descending | Select-Object -ExpandProperty Name -Skip 1 | Remove-Item
Remove-Item : Cannot find path 'D:\FM\r_2-2.exe' because it does not exist.
At line:1 char:251
+ ... Descending | Select-Object -ExpandProperty Name -Skip 1 | Remove-Item
I know about foreach loop but want to use For-EachObject cmdlet instead.
You were quite close, if you want to use ForEach-Object:
Get-ChildItem $P -Filter *.exe | Where-Object Name -Like '*r_2-2*' | Select-Object -Skip 1 | ForEach-Object { remove-item $_.FullName -force }
To skip one first found result just Select-Object -Skip 1 is enough.
Remove-Item -Force also removes hidden and read-only files.
You can make the use of FullName parameter directly in your statement. Try this -
$C = Get-ChildItem $P -Filter *.exe| Where-Object Name -Like '*r_2-2*' | Sort-Object Name -Descending | Select-Object -ExpandProperty FullName -Skip 1
$c | ForEach-Object {Remove-Item -Path $_}
Use -Force parameter if you want to delete the hidden files too.

Powershell find folders, delete files leaving latest 5

We use software called Revit, files are saved as such: filename.rvt
Each time a user edits a file, Revit takes it upon itself to save the old file in the format filename.xxxx.rvt (where xxx is a number).
Over time when files are edited hundreds of times, we have many unnecessary files on the file server.
I am writing a script to:
Locate and folders containing Revit backup files
Delete all but the most recently modified 5 revit backup files
I have tried two approaches below
$searchpath = "e:\"
# Find a unique list of directories that contains a revit backup file (*.*.rvt)
$a = Get-ChildItem -Path $searchpath -Include *.*.rvt -Recurse | Select-object Directory -expandproperty FullName | Get-Unique -AsString
# For each folder that contains a single revit backup file (*.*.rvt)...
# - Sort by modified time
# - Select all except first 5
$a | Get-ChildItem -Include *.*.rvt | Sort-Object LastWriteTime -descending | select-object -skip 5 -property Directory,Name,CreationTime,LastWriteTime | Out-GridView -Title "Old Backups" -PassThru
The issue with this approach is that it only "skips" the first 5 files in the entire search result, not 5 in each folder.
Then I went about it using a loop, and this gets nowhere:
$searchpath = "e:\"
# Find a unique list of directories that contains a revit backup file (*.*.rvt)
$a = Get-ChildItem -Path $searchpath -Include *.*.rvt -Recurse | Select Directory | Get-Unique -AsString
# For each folder that contains a single revit backup file (*.*.rvt)...
# - Sort by modified time
# - Select all except first 5
$a | foreach {
$b += Get-ChildItem -Path $_.Directory.FullName -Include *.*.rvt | Sort-Object LastWriteTime -descending | select-object -skip 5 -property Directory,Name,CreationTime,LastWriteTime
}
$b | Out-GridView -Title "Old Backups" -PassThru
Any thoughts on the correct approach and whats going wrong?
try this:
get-childitem -file -recurse | group Directory | where Count -gt 5 | %{
$_.Group | Sort LastWriteTime -descending | select -skip 5 Directory,Name,CreationTime,LastWriteTime
} | Out-GridView -Title "Old Backups"
If you want delete you can do it (remove what if)
gci -file -recurse | group Directory | where Count -gt 5 | %{
$_.Group | Sort LastWriteTime -descending | select -skip 5 | remove-item -WhatIf
}
The key to do what you seek is to use the Group-Object cmdlet.
In your case, the group you want to create is a group containing all items in the same folder. This will give you something like this:
From there, you can perform actions on each group, such as selecting all the files while skipping the first 5 of each folders and deleting the remaining.
See this simple minimalist example:
$Path = 'C:\__TMP\1'
$Items = Get-ChildItem -Path "$path\*.rvt" -Recurse | Group-Object -Property PsparentPath
Foreach ($ItemsGroup in $Items) {
$SortedFiles = $ItemsGroup.Group | sort LastWriteTime -Descending
$SortedFiles | Select-Object -Skip 5 | % {Write-host "Deleting $($_.FullName)"; Remove-Item $_.FullName}
}
Try something like this:
$searchpath = "E:\"
$number = 5
$directories = Get-ChildItem -Path $searchpath -Include *.*.rvt -Recurse | Where-Object {$_.PsIsContainer}
foreach ($dir in $directories)
{
$files = Get-ChildItem -Path $dir.FullName | Where-Object {-not $_.PsIsContainer}
if ($files.Count -gt $number)
{
$files | Sort-Object CreationTime | Select-Object -First ($files.Count - $number) | Remove-Item -Force
}
}
Change the placeholders accordingly. I just gave you the logical approach.
An alternative solution that doesn't require grouping first and instead processes each directory separately:
& { Get-Item $path; Get-ChildItem -Directory -Recurse $path } | # get all dirs.
ForEach-Object { # for each dir.
Get-ChildItem -File $_.FullName/*.*.rvt | # get backup files in dir.
Sort-Object -Descending LastWriteTime | # sort by last-write time, newest first
Select-Object -Skip 5 | # skip the 5 newest
Remove-Item -Force -WhatIf # delete
}
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.