I am working on some PowerShell script that automatically moves folders and files from the 'X-Drive' folder and move it into the 'Old' folder which also is inside the 'X-Drive' folder, but I want it to keep the first layer folders only, all what's inside can be moved but only the folder needs to be kept, but it also needs to be in the 'Old' folder.
$exclude = #('Keep 1', 'Keep 2')
Get-ChildItem -Path "C:\X-Drive" -Recurse -Exclude $exclude |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-0) } |
Move-Item -Destination "C:\X-Drive\Old" -ErrorAction 'SilentlyContinue'
Enumerate the subfolders of C:\X-D_rive, then move their content to corresponding subfolders in C:\X-Drive\old, e.g. like this:
$refdate = (Get-Date).AddDays(-1)
Get-ChildItem 'C:\X-Drive' -Directory -Exclude $exclude | ForEach-Object {
$dst = Join-Path 'C:\X-Drive\old' $_.Name
If (-not (Test-Path -LiteralPath $dst)) {
New-Item -Type Directory -Path $dst | Out-Null
}
Get-ChildItem $_.FullName -Recurse | Where-Object {
$_.LastWriteTime -lt $refdate
} | Move-Item -Destination $dst
}
You may want to add old to $excludes, BTW.
The code assumes you're running PowerShell v3 or newer.
Related
I'm pretty new to Powershell in general, I've come across some partial solutions, but I can't find the right fit.
Ideally I would like to Archive (Zip) with Powershell but only files of a certain age (x days/months), but I would prefer keeping the folder structure and also add exclusions.
Here's what I've been trying to use (without success):
$inputFolder = "C:\Temp\Test"
$excludeFolders = #("\subfolderToKeep")
$ouputFileName="C:\Temp\archive.zip"
$Daysback = "-5"
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
$tempFolder = [System.IO.Path]::GetTempFileName()
Remove-Item $tempFolder -Force
New-Item -Type Directory -Path $tempFolder -Force
$exclude =#()
$excludeFolders | ForEach-Object {
$exclude+=(Join-Path $inputFolder $_)
Get-ChildItem (Join-Path $inputFolder $_) -Recurse |
ForEach-Object{$exclude+=$_.FullName}}
Get-ChildItem $inputFolder -Recurse | Where-Object { $_.FullName -notin $exclude -and $_.LastWriteTime -lt $DatetoDelete } |
Copy-Item -Destination {Join-Path $tempFolder $_.FullName.Substring($inputFolder.length)}
Get-ChildItem $tempFolder |
Compress-Archive -DestinationPath $ouputFileName -Update
The current setup would work without the date filtering:
-and $_.LastWriteTime -lt $DatetoDelete
I'm having problems to create a PS command that allows me to delete several subfolders without deleting the roof folder.
I.E:
C:\Test has many subfolders:
C:\Test\Item1
C:\Test\Item2
C:\Test\Item3
And the folders Item1, Item2 and Item3 have many subfolders and files.
I would like to create a PS that would allow me to delete all the empty subfolders inside Item1, Item2 and Item3 without deleting Item1, Item2 and Item3 folders. It is possible that any of the Item folders is empty, but I don't want to delete them, just the empty content of each folder.
This is just an example, I have a have around 300 Item folders inside Test.
I usually would use this:
$path="C:\TEST"
do {
$dir = gci $path -directory -recurse | Where { (gci $_.fullName).count -eq 0 } | select -expandproperty FullName
$dir | Foreach-Object { Remove-Item $_ }
} while ($dir.count -gt 0)
But this deletes the folder root folder (Item1, Item2 or Item3) if they are empty.
Thanks in advance.
So you are looking to delete All Items inside Empty Subfolders or all items in General?
This will delete all Folders or Items in General inside of the Directory "C:\abc\"
$path = "C:\abc\"
Get-ChildItem -Path $path -Recurse| Foreach-object {Remove-item -Recurse -path $_.FullName }
This will delete all Folders that dont have any items in them.
$path = "C:\abc\"
Get-ChildItem -Path $path -Recurse | Where-Object {(Get-ChildItem $_.FullName).Count -eq 0} |Foreach-object {Remove-item -Recurse -path $_.FullName }
ยด
This will look inside "C:\abc\" Get all the children and delete all empty Directories inside the Children in your example this would be Item1,Item2,...
$Path = "C:\abc\"
$itemFolders= Get-ChildItem -Path $Path
$itemFolders| Foreach-Object {
Get-ChildItem -Path $_.FullName |
Where-Object {(Get-ChildItem $_.FullName).Count -eq 0} |
Foreach-object {Remove-item -Recurse -path $_.FullName }
}
Just a quick and dirty bit of Code as I dont have much time, hope I could be of help.
EDIT: Here is what i came up with, its not as performant as I'd like but it gets the job done and is fairly quick, try it out for yourself it worked for me - even threw in a couple of comments and output to clarify what's going on.
$Path="C:\abc\"
$itemFolders = Get-ChildItem $Path
#Get All Folders inside
$AllFolders = $itemFolders | Get-ChildItem -Recurse | Where-Object {$_.PSIsContainer} | Select -Property FullName
#First delete all files older than 30 days
$itemFolders | Get-ChildItem -Recurse -File | ForEach-Object{
$limit = (Get-Date).AddDays(-30)
if($_.LastWriteTime -lt $limit)
{
"{0} hasn't been modified in the last 30 days deleting it" -f $_.FullName
Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue
}
}
#Check if there are files inside that are not containers
$AllFolders | ForEach-Object{
$files = Get-ChildItem -File -Recurse -Path $_.FullName
$directories = Get-ChildItem -Directory -Recurse -Path $_.FullName
#If There are any files inside the folder dont delete it.
if($files.Count -gt 0)
{
"Found {0} files inside {1} do not delete this" -f $files.Count, $_.FullName
}
#If There are no files and no directories inside delete it.
elseif($files.Count -eq 0 -and $directories.Count -eq 0)
{
"Empty Folder {0} deleting it" -f $_.FullName
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
}
#If there are no files and empty directories inside delete it.
elseif($files.Count -eq 0 -and $directories.Count -gt 0)
{
"No Files but directories found in {0} since its recursive delete it" -f $_.FullName
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
}
}
I'm trying to zip all files in all subdirectories that are older than 31 days.
The following code mainly works, but does some things wrong. It creates new folders and zips them, as desired.
But, it doesn't seem to move the old files into the newly-created directories befoee they are zipped. The line Get-ChildItem -Exclude *.zip | ? {$_.LastWriteTime -lt (Get-date).AddDays(-31) -and -not $_.psIsContainer} | Move-Item -destination $newpath should do that, but doesn't. When I try to run it on its own in the console, it works fine however.
Also, in a tree of folders, this code won't work on the outer edges of the tree. What I mean is that the last folder will not have a new folder created within it.
Does anyone know where I'm going wrong?
function zipfiles ($path,$name){
$date = "$((Get-Date).ToString('yyyy-MM-dd'))"
$newpath = "$path$date"
New-Item -ItemType Directory -Path $newpath
Get-ChildItem -Exclude *.zip | ? {$_.LastWriteTime -lt (Get-date).AddDays(-31) -and -not $_.psIsContainer} | Move-Item -destination $newpath
[Reflection.Assembly]::LoadWithPartialName( "System.IO.Compression.FileSystem" )
$src_folder = $newpath
$destfile = "$newpath.zip"
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
$includebasedir = $false
[System.IO.Compression.ZipFile]::CreateFromDirectory($src_folder,$destfile,$compressionLevel, $includebasedir)
Remove-Item $newpath -recurse
}
Get-ChildItem -Recurse -Directory | ForEach-Object { zipfiles($($_.FullName),$($_.Name))}
There is a directory where I am moving folders, from a different directory without any logic(randomly anytime) and these folders needs to be deleted after 10 days of their moving here.
So, will this work? -
$limit = (Get-Date).AddDays(-10)
$path = "C:\Some\Path"
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force
What I don't know is that this creation time parameter would be updated when I move it to the new directory???
As requested in comments, a solution with renaming folders:
Moving a folder:
$sOldPath = "C:\oldpath\foldertomove" # Change to your actual path
$sNewPath = "C:\newpath" # Change to your actual new path
$sDate = Get-Date -Format "yyyMMdd"
$oFolderToMove = Get-Item -Path $sOldPath
Move-Item -Path $sOldPath -Destination $sNewPath
Rename-Item -Path (Join-Path -Path $sNewPath -ChildPath $oFolderToMove.Name) `
-NewName ("{0}-{1}" -f $sDate, $oFolderToMove.Name)
Resulting path: C:\newpath\yyyyMMdd-foldertomove
Deleting old folders:
$sNewPath = "C:\newpath" # Change to your actual new path
$sDateLimit = ((Get-Date).AddDays(-10)).ToString("yyyyMMdd")
# Assuming that all folders in $sNewPath have date-prefixed names.
Get-ChildItem -Path $sNewPath |
Where-Object { $_.PSIsContainer } |
Foreach-Object {
$sDate = [UInt32]($_.Name.Substring(0,8))
if ($sDate -lt $sDateLimit) {
# Deletes folder and everything in it. Remove -WhatIf switch to execute.
Remove-Item -Path $_.FullName -Recurse -Force -WhatIf
}
}
I have a folder whose entire entire contents I want to delete, but I want to keep the actual folder. I have tried this:
function deleteFiles {
# The parameter.
param([string]$sourceDir)
# Move the files
Get-ChildItem -Path $sourceDir -Include *.* -Recurse | foreach { $_.Delete()}
#Delete empty directories
Get-ChildItem -Path $sourceDir -recurse | Where-Object {
$_.PSIsContainer -eq $true -and (Get-ChildItem -Path $_.FullName) -eq $null
} | Remove-Item
}
However as one of the subdirectories has its own sub directories they aren't deleted.
This should suffice:
Remove-Item -Path "$sourceDir\*" -Recurse