Remove certain folders recursively? - powershell

I've a folder structure that looks like this
-2018
--01-Jan
--02-Feb
--etc
-2017
--01-Jan
--02-Feb
--etc
Is there a way to delete all directories that are over 7 years old (according to this naming structure ... not according to Creation / Modified Date etc)?
So if I ran it in August 2018 I would be left with
-2018
-2017
-2016
-2015
-2014
-2013
-2012
-2011
--08-Aug
--09-Sep
--10-Oct
--11-Nov
--12-Dec
So the 2012 - 2018 folders would remain untouched.
Any folder 2010 and earlier would be deleted.
And any folder within 2011 '07-Jul' or smaller would be deleted.
Thanks
P

I first created a comparable folder structure using this code:
##
## define enum for months
##
enum month {
Jan = 1
Feb = 2
Mar = 3
Apr = 4
May = 5
Jun = 6
Jul = 7
Aug = 8
Sep = 9
Oct = 10
Nov = 11
Dec = 12
}
##
## create folder structure
##
New-Item -Path c:\ -Name Testdata -ItemType Directory
2018..2005 |
foreach {
New-Item -Path c:\Testdata -Name $psitem -ItemType Directory
$path = "c:\Testdata\$psitem"
1..12 |
foreach {
$name = "{0:00}-{1}" -f $psitem, [month]$psitem
New-Item -Path $path -Name $name -ItemType Directory
}
}
That gives me an easy structure to test. I'm assuming that your year folders are subfolders of something. If they are in the root of a drive that works as well.
To delete the folders:
enum month {
Jan = 1
Feb = 2
Mar = 3
Apr = 4
May = 5
Jun = 6
Jul = 7
Aug = 8
Sep = 9
Oct = 10
Nov = 11
Dec = 12
}
$date = Get-Date
$year = $date.Year - 8
##
## delete evreything 8 years or older
##
Get-ChildItem -Path C:\Testdata -Directory |
where Name -le $year |
foreach {
Remove-Item -Path $psitem.Fullname -Recurse -Force -Confirm:$false
}
##
## if Month -ne January
## need to delete some months
##
if ($date.Month -gt 1){
$path = "C:\testdata\$($year+1)"
$month = $date.Month -1
1..$month |
foreach {
$mpath = "$path\{0:00}-{1}" -f $psitem, [month]$psitem
Remove-Item -Path $mpath -Recurse -Force -Confirm:$false
}
}
I'm making an assumption about the three letter abbreviations you use but you can easily change the enum.
The code gets the current date and gets the year minus 8. It loops through your top level folder and gets the folders that are less than or equal to the year you've defined. They, and their contents, are force deleted. Only thing that could stop the deletion is if you have one of the files pinned open.
If the current month is January there's nothing else to do. Otherwise create the path to the -7 year folder and calculate the last month you want to delete. Loop through the months, build the path and force the deletion of the folder and its contents.
The bulk of the work is done at the year level with a quick clean up of the months. I'd suggest testing against a number of months to check the logic is what you need.

Okay, this is very simple and it will require you to do some coding and using a nested loop essentially. What you need to understand is how to use the Get-Date verb. So a sample that will remove all data recursively before 2011 would look like this
# Set your Path
$MyFolderPath = "C:\MyPath"
# Define the object to hold the folders (We are only looking for Folders not files)
$folders = Get-Childitem -Path $MyFolderPath -Directory
# Loop through each folder
foreach($folder in $folders)
{
# Using a cast to integer compare the Year using the folder name with the
# Get-Date function -7 years from this year
if([int]$folder.Name -lt (Get-Date).AddYears(-7).Year)
{
# Now remove the entire folder recursively without prompting.
Remove-Item $folder.FullName -Recurse -Force -Confirm:$false
}
}
Now to achieve it to the level of the month. I will let you play around with a nested loop and get through to that level. I hope this helps you...

Related

Powershell Script to create folder by week number for 2022

I am trying to create a folder by week number so far i am able to create it for the current week however i would like to create it for the entire year i.e. 2022 under the respective months i.e. March April etc.. All the week number folders should be created inside these folders.
$currentweek = "{0:d1}" -f ($(Get-Culture).Calendar.GetWeekOfYear((Get-Date),[System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [DayOfWeek]::Monday))
$destFolder = New-Item -Path C:\C:\Users\MAdmin\Documents\VA05\2022\March\Week_$currentweek -Type Directory -ErrorAction SilentlyContinue ```
If I understand correctly, you would like to create a folder tree of week numbers in the year 2022, because as you have commented in reply of Tomalak's comment, creating these weeknumber subfolders inside Monthname folders can hardly be done correctly since weeknumbers can overlap months.
To do this, I would use a helper function to obtain the first Thursday of the first week in the year. (ISO 8601 dictates that week 1 starts with the week that has a Thursday in it):
function Get-FirstThursday {
param(
[Parameter(Mandatory = $false, Position = 0)]
[int]$Year = [DateTime]::Now.Year,
[Parameter(Mandatory = $false, Position = 1)]
[int]$WeekNumber = [CultureInfo]::InvariantCulture.Calendar.GetWeekOfYear([DateTime]::Now,
[System.Globalization.CalendarWeekRule]::FirstFourDayWeek,
[DayOfWeek]::Monday)
)
$january1 = [DateTime]::new($Year,1,1,0,0,0,[System.DateTimeKind]::Local)
$offset = [int]([DayOfWeek]::Thursday - $january1.DayOfWeek)
$thursday1 = $january1.AddDays($offset)
# ISO 8601
$week1 = [CultureInfo]::InvariantCulture.Calendar.GetWeekOfYear($thursday1,
[System.Globalization.CalendarWeekRule]::FirstFourDayWeek,
[DayOfWeek]::Monday)
if($week1 -le 1) { $WeekNumber -= 1 }
# return the date for the first Thursday of the week in the given year
$thursday1.AddDays($WeekNumber * 7)
}
Having that function on top of the script, you can create the folders like:
$destination = 'C:\Users\MAdmin\Documents\VA05'
$year = (Get-Date).Year # 2022
# get the first Thursday of week 1 in the given year
$thursday = Get-FirstThursday -Year $year -WeekNumber 1
# keep adding 7 days to this first Thursday until we reach next year
# create weeknumber subfolders (most years 52, some years 53)
$week = 0
while ($thursday.Year -eq $year) {
$thursday = $thursday.AddDays(7)
$week++
# create a subfolder for this weeknumber
$targetFolder = Join-Path -Path $destination -ChildPath ('{0}\{1:D2}' -f $year, $week)
$null = New-Item -Path $targetFolder -ItemType Directory -Force
}

Creating multiple folders with dates etc. 190101 to 191231

I'm trying to create multiple folders but for dates in a year.
Also, I have been using PowerShell and trying to create a batch script.
I had tried several solutions, but no one of them gives me what I need.
So, I need to create folders as 190101 to 191231 empty once for all year. But whatever I do I don't get what I want.
Examples:
01..31 | foreach $_{ New-Item -ItemType Directory -Name $("1901" + $_)}
mkdir $(01..31 | %{"ch$_"})
md(01..31|%{"1901$_"})
But the problem here they don't give me 0 in "days" so, I have
19011 instead of 190101.
I can't find how to extract dates and push PowerShell to create what I need.
here is a slightly more generalized version that will work for any given month. the -f string format operator is really quite handy ... [grin]
$Today = (Get-Date).Date
$Year = $Today.Year
$Month = $Today.Month
$DaysInMonth = (Get-Culture).Calendar.GetDaysInMonth($Year, $Month)
foreach ($Day in 1..$DaysInMonth)
{
'{0}{1:D2}' -f $Today.ToString('yyMM'), $Day
}
truncated output ...
190101
190102
[*...snip...*]
190130
190131
One way to create folders for every day of the year
define/get the year
set start date to Jan 1st
to have a zero based offset get the DayOfYear for the 30th December
use a range to AddDays to startdate and iterate
$year = (Get-Date).Year
$startdate = Get-Date -Year $year -Month 1 -Day 1
0..(Get-Date -Year $year -Month 12 -Day 30).DayOfYear| ForEach-Object{
mkdir ($startdate.AddDays($_).ToString('yyMMdd')
)
Use the format operator (-f). It was made for this exact purpose.
1..31 | ForEach-Object {
New-Item -Type Directory -Name ('1901{0:d2}' -f $_)
}

powershell date comparision need to delete file

i have to make powershell file where i need to compare 2 dates and delete folder which is like more than 10 days of last write item . like today is 30 October i need to delete folder where comparision of dates give 11 12 and 13 days
#ChildItem "\\server\Backup" -Recurse | Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays.(-30) }
#$fulllist =Get-ChildItem "\\server\Backup\SharePoint Backup\"| Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays.(5) }
$fulllist =Get-ChildItem "\\server\Backup\SharePoint Backup\"
#$fulllist =Get-ChildItem "\\server\Backup\SharePoint Backup\" -Recurse | Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays.(-20) }
foreach ($fileitem in $fulllist)
{
$filename_big = $fileitem.FullName
#write-host $filename_big
$d = [datetime](Get-ItemProperty -Path $filename_big -Name LastWriteTime).lastwritetime
$d1=(get-date)
#write-host $d
#write-host $d1
$ts = New-TimeSpan -Start $d -End $d1
$ts.Days # Check results\
write-host $ts
if($ts -gt 10)
{
write-host "inside"
}
# Move-Item -Path $filename_big -Destination "\\DBORION\d$\backup"
}
iam comparing two dates $d & d1 and days are greater than 10 that folders should get deleted.
but with output iam getting its going inside for all folders whether its 10 days or 5 days ,please find output
0
00:58:29.2923431
inside
0
13:33:32.4388907
inside
0
07:02:28.0900378
inside
0
03:52:35.3425970
inside
0
00:58:29.4017400
inside
13
13.08:49:05.4930775
inside
12
12.08:49:06.3403154
inside
11
11.08:48:31.4681438
inside
10
10.08:48:18.6859604
inside
9
9.08:49:01.2220544
inside
8
8.08:39:56.7230423
inside
7
7.08:48:15.3242000
inside
6
6.08:49:03.6123002
inside
5
5.08:49:08.5439345
inside
4
4.08:49:06.6188386
inside
3
3.08:49:07.2066345
inside
2
2.08:49:06.2290185
inside
1
1.08:45:07.0454477
inside
0
08:47:24.1939025
inside
ok so i got this
$fulllist = Get-ChildItem "\\Server\Backup\SharePoint Backup\"
$Days = 12
foreach ($fileitem in $fulllist)
{
$filename_big = $fileitem.FullName
$deletedate = (Get-Date).AddDays(-$Days)
$Folderdate = [datetime](Get-ItemProperty -Path $filename_big -Name LastWriteTime).lastwritetime
if($Folderdate -le $deletedate)
{
$filename_big
Remove-Item -Path $filename_big -Force -Confirm:$false
}
}
now my only concern is its asking for confirmation of deletion, i dont want that popup box how to bypass that
I think the problem is that your variable $ts is a timespan. A timespan can never be greater then 10, because it is a number. In your if clause you should use:
if($ts.Days -gt 10)
And some other maybe needfull advices to spare some byte:
when you define your $d variable, this can be done much shorter: $d = $fileitem.lastwritetime - the $fileitem variable itself has the lastwritetime property.
when assigning a function to a variable, there is no need for round brackets: just use $d1 = Get-Date. The brackets are only needed if you want to assign a propery of the function, for example $d = (Get-Date).DayOfWeek.
you could avoid creating the timespan by this: if($d -gt $d1.addDays(-10)). This compares your file timestamp $d with the current time minus 10 days, meaning the point in time exactly 10 days ago.
And to bypass confirmation when you delete files: use the -force parameter.

How to compare to string in PowerShell foreach loop to files

How to compare the current month with file modified in current month using power shell script. My code is working file but it is reading all the csv file in the given directory. I just wanted to read current month file i.e. modified in October 2018.
Please help me out , I have total 6 files in my directory. 3 files having date modified in October 2018 and remaining 3 files are modified in September 2018.
I want my script to check the current month then read all csv of current month i.e. October 2018
Code:
$files = Get-ChildItem 'C:\Users\212515181\Desktop\Logsheet\*.csv'
$targetPath = 'C:\Users\212515181\Desktop\Logsheet'
$result = "$targetPath\Final.csv"
$curr_month = (Get-Date).Month
$curr_year = (Get-Date).Year
# Adding header to output file
[System.IO.File]::WriteAllLines($result,[System.IO.File]::ReadAllLines($files[1])[1])
foreach ($file in $files)
{
$month = $file.LastWriteTime.ToString()
$curr_month=(Get-Date).Month
if ($month= $curr_month)
{
$firstLine = [System.IO.File]::ReadAllLines($file) | Select-Object -first 1
[System.IO.File]::AppendAllText($result, ($firstLine | Out-String))
$lines = [System.IO.File]::ReadAllLines($file)
[System.IO.File]::AppendAllText($result, ($lines[2..$lines.Length] | Out-String))
}
}
# Change output file name to reflect month and year in MMYYYY format
Rename-Item $result "Final_$curr_month$curr_year.csv"
Your comparison is wrong. And will return $true causing all files to be read
It should be
if ($month -eq $curr_month)
Also I would remove the second
$curr_month = (get-date).month
it's adding overhead to your script as you set it before the loop

creating powershell script to backup a file and append the date

Currently I have a one line batch file to back up a file. I run it manually when I need to back up a file. The only thing I would like to add to it is the current date. Here is what I have:
xcopy /W /Y ACTIVE.DB ACTIVE.DB.BACKUP
the destination file should simply be ACTIVE.DB.BACKUP.YYYYMMDD. How would I go about creating a script that will allow me to double click on it from Windows Explorer and make the xcopy happen?
Just to point out that you can do this with Copy-Item e.g.:
Set-Location $path
Copy-Item ACTIVE.DB "ACTIVE.DB.$(get-date -f yyyyMMdd)" -Force -Confirm
If you're going for robust then I'd use robocopy.exe.
You can customize your filename by embedding a formatted [datetime]::now in the file name in PowerShell like so:
xcopy /W /Y ACTIVE.DB "ACTIVE.DB.BACKUP.$([datetime]::now.ToString('yyyy-MM-dd'))"
If the line feels busy and unmaintainable, you can refactor it to multiple lines:
$now = [datetime]::now.ToString('yyyy-MM-dd')
xcopy /W /Y ACTIVE.DB "ACTIVE.DB.BACKUP.$now"
To get double-click execution, I usually make a batch file that runs the PowerShell command as described here:
Set up PowerShell Script for Automatic Execution
I just made a Daily/Weekly/Monthly/Quarterly/Yearly backup script in Powershell this month, and hope it helps.
This DWMQY backup scenario is to zip a source folder to a date-named zip file, then keep the zips of:
last 7 days
4 weeks (each Friday's)
6 months (the last Friday's of each month)
4 quarters (the last month's of quarter)
2 years (the last quarter's of year).
Running as scheduled task on daily basis, it puts the zips into a target folder which is also a Microsoft OneDrive's local folder, so the zips also being remotely sync'd to OneDrive server. Those outdated (non-Friday daily or non-last-DWMQY) zips will be moved to a non-remotely-sync'd folder.
It's March 5, 2016 today, the following zips should be in the target folder:
7 days: 160304-160229-160227
4 weeks: 160304, 160226, 160219,160212
6 months: 160226, 160129, 161225, 151127, 151025, 150925
4 quarters: 151225, 150925,150626,150327
2 years: 151225, 141226
So there will be 23 zips (actually less since the dups among DWMQY), our files are 250 text documents which is 0.4 GB after zipping, so it's 23*0.4 = 9.2 GB in total, which is less than OneDrive free 15 GB quota.
For large source data, 7-zip can be used, which provides maximum 16 mil TB zip size. For directly backup folders instead of zips, haven't tried. Guessing it's a transferable procedure from the current zip way.
# Note: there are following paths:
# 1. source path: path to be backed up.
# 2. target path: current zips stored at, which is also a remote-sync pair's local path.
# 3. moved-to path: outdated zips to be moved in this non-sync'able location.
# 4. temp path: to copy the source file in to avoid zip.exe failing of compressing them if they are occupied by some other process.
# Function declaration
. C:\Source\zipSaveDated\Functions.ps1
# <1> Zip data
$sourcePath = '\\remoteMachine1\c$\SourceDocs\*'
$TempStorage = 'C:\Source\TempStorage'
$enddate = (Get-Date).tostring("yyyyMMdd")
$zipFilename = '\\remoteMachine2\d$\DailyBackupRemote\OneDrive\DailyBackupRemote_OneDrive\' + $enddate + '_CompanyDoc.zip'
Remove-Item ($TempStorage + '\*') -recurse -Force
Copy-Item $sourcePath $TempStorage -recurse -Force
Add-Type -A System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::CreateFromDirectory($TempStorage, $zipFilename)
# <2> Move old files
$SourceDir = "\\remoteMachine2\d$\DailyBackupRemote\OneDrive\DailyBackupRemote_OneDrive"
$DestinationDir = "\\remoteMachine2\d$\DailyBackupRemote\bak" # to store files moved out of the working folder (OneDrive)
$KeepDays = 7
$KeepWeeks = 4
$KeepMonths = 6
$KeepQuarters = 4
$KeepYears = 2
# <2.1>: Loop files
$Directory = $DestinationDir
if (!(Test-Path $Directory))
{
New-Item $directory -type directory -Force
}
$files = get-childitem $SourceDir *.*
foreach ($file in $files)
{ # L1
# daily removal will not remove weekly copy, 7
If($file.LastWriteTime -lt (Get-Date).adddays(-$KeepDays).date `
-and $file.LastWriteTime.DayOfWeek -NotMatch "Friday" `
)
{
Move-Item $file.fullname $Directory -force
}
} # L1 >>
$files = get-childitem $SourceDir *.*
foreach ($file in $files)
{ # L1
# weekly removal will not remove monthly copy, 4
If($file.LastWriteTime -lt (Get-Date).adddays(-$KeepWeeks * 7).date `
-and (Get-LastFridayOfMonth ($file.LastWriteTime)).Date.ToString("yyyyMMdd") -NotMatch $file.LastWriteTime.Date.ToString("yyyyMMdd")
)
{
Move-Item $file.fullname $Directory -force
}
} # L1 >>
$files = get-childitem $SourceDir *.*
foreach ($file in $files)
{ # L1
# monthly removal will not remove quarterly copy, 6
If($file.LastWriteTime.Month -lt ((Get-Date).Year - $file.LastWriteTime.Year) * 12 + (Get-Date).Month - $KeepMonths `
-and $file.LastWriteTime.Month -NotIn 3, 6, 9, 12
)
{
Move-Item $file.fullname $Directory -force
}
} # L1 >>
$files = get-childitem $SourceDir *.*
foreach ($file in $files)
{ # L1
# quarterly removal will not remove yearly copy, 4
If($file.LastWriteTime.Month -lt ( (Get-Date).Year - $file.LastWriteTime.Year) * 12 + (Get-Date).Month - $KeepQuarters * 3 `
-and $file.LastWriteTime.Month -NotIn 12
)
{
Move-Item $file.fullname $Directory -force
}
} # L1 >>
$files = get-childitem $SourceDir *.*
foreach ($file in $files)
{ # L1
# yearly removal will just go straight ahead. 2
If($file.LastWriteTime.Year -lt (Get-Date).Year - $KeepYears )
{
Move-Item $file.fullname $Directory -force
}
} # L1 >>
<Functions.ps1>
function Get-TimesResult3
{
Param ([int]$a,[int]$b)
$c = $a * $b
Write-Output $c
}
function Get-Weekday {
param(
$Month = $(Get-Date -format 'MM'),
$Year = $(Get-Date -format 'yyyy'),
$Days = 1..5
)
$MaxDays = [System.DateTime]::DaysInMonth($Year, $Month)
1..$MaxDays | ForEach-Object {
Get-Date -day $_ -Month $Month -Year $Year |
Where-Object { $Days -contains $_.DayOfWeek }
}
}
function Get-LastFridayOfMonth([DateTime] $d) {
$lastDay = new-object DateTime($d.Year, $d.Month, [DateTime]::DaysInMonth($d.Year, $d.Month))
$diff = ([int] [DayOfWeek]::Friday) - ([int] $lastDay.DayOfWeek)
if ($diff -ge 0) {
return $lastDay.AddDays(- (7-$diff))
}
else {
return $lastDay.AddDays($diff)
}
}