I am new to powershell. I have created a script to copy files according to year & month, and then zip it. My code is working fine, because I am noob in powershell, and just wrote same command again and again. Can someone help me reduce my lines in the codes?
$Source = "C:\Users\abhishek.y.verma\OneDrive - Accenture\Desktop\My-Info"
$Target = "C:\Users\abhishek.y.verma\OneDrive - Accenture\Desktop\Power"
$Year1 = 2022
$Year2 = 2021
$Year3 = 2020
$Year4 = 2019
$Year5 = 2018
$files = Get-ChildItem -LiteralPath $Source -Recurse -File
#Get the names of the files
$filesFromYear1 = $files | Where-Object {$_.CreationTime.Year -eq $Year1}
$filesFromYear2 = $files | Where-Object {$_.CreationTime.Year -eq $Year2}
$filesFromYear3 = $files | Where-Object {$_.CreationTime.Year -eq $Year3}
$filesFromYear4 = $files | Where-Object {$_.CreationTime.Year -eq $Year4}
#Make Folder for each month
foreach($i in 1..12) {
New-Item -Path $Target\$Year1 -Name $i -ItemType "directory"
New-Item -Path $Target\$Year2 -Name $i -ItemType "directory"
New-Item -Path $Target\$Year3 -Name $i -ItemType "directory"
New-Item -Path $Target\$Year4 -Name $i -ItemType "directory"
New-Item -Path $Target\$Year5 -Name $i -ItemType "directory"
}
#Move Files:
foreach($j in 1..12) {
$filesMonthly1 = $files | Where-Object { ($_.CreationTime.Year -eq $Year1) -and ($_.CreationTime.Month -eq $j) }
$filesMonthly1 | Copy-Item -Destination $Target\$Year1\$j
Compress-Archive -Path $Target\$Year1\$j -Destination $Target\$Year1\$j.zip
$filesMonthly2 = $files | Where-Object { ($_.CreationTime.Year -eq $Year2) -and ($_.CreationTime.Month -eq $j) }
$filesMonthly2 | Copy-Item -Destination $Target\$Year2\$j
Compress-Archive -Path $Target\$Year2\$j -Destination $Target\$Year2\$j.zip
$filesMonthly3 = $files | Where-Object { ($_.CreationTime.Year -eq $Year3) -and ($_.CreationTime.Month -eq $j) }
$filesMonthly3 | Copy-Item -Destination $Target\$Year3\$j
Compress-Archive -Path $Target\$Year3\$j -Destination $Target\$Year3\$j.zip
$filesMonthly4 = $files | Where-Object { ($_.CreationTime.Year -eq $Year4) -and ($_.CreationTime.Month -eq $j) }
$filesMonthly4 | Copy-Item -Destination $Target\$Year4\$j
Compress-Archive -Path $Target\$Year4\$j -Destination $Target\$Year4\$j.zip
$filesMonthly5 = $files | Where-Object { ($_.CreationTime.Year -eq $Year5) -and ($_.CreationTime.Month -eq $j) }
$filesMonthly5 | Copy-Item -Destination $Target\$Year5\$j
Compress-Archive -Path $Target\$Year5\$j -Destination $Target\$Year5\$j.zip
}
CodePudding user response:
Use Where-Object
once, to test that the year is one of the years you're interested in, then use Group-Object
to group them all together - at which point you just need to repeat the same operation for each group:
$Source = "C:\Users\abhishek.y.verma\OneDrive - Accenture\Desktop\My-Info"
$Target = "C:\Users\abhishek.y.verma\OneDrive - Accenture\Desktop\Power"
$Years = 2022..2019
# discover files in scope
$files = Get-ChildItem -LiteralPath $Source -Recurse -File |Where-Object {$_.CreationTime.Year -in $Years}
# group by creation year
$files |Group-Object { $_.CreationTime.Year } |ForEach-Object {
# extract year of current group
$year = $_.Name
foreach($month in 1..12){
# create the target directory
$newMonthFolder = New-Item -Path $Target\$year -Name $month -ItemType "directory"
# copy relevant files
$_.Group |Where-Object {$_.CreationTime.Month -eq $month} |Copy-Item -Destination $newMonthFolder.FullName
# create zip
Compress-Archive -LiteralPath $newMonthFolder.FullName -Destination $Target\$Year\$month.zip
}
}
CodePudding user response:
Code
$Source = "C:/Users/Megam/Desktop/A-1"
$Target = "C:/Users/Megam/Desktop/B-1"
$initialYear = 2018
$finalYear = 2022
$validFiles = Get-ChildItem -LiteralPath $Source -Recurse -File | Where-Object { $_.CreationTime.Year -in ($initialYear..$finalYear)}
($initialYear..$finalYear) | ForEach-Object {
$year = $_
$files = $validFiles | Where-Object { $_.CreationTime.Year -eq $year} # Get files of year.
if($files.Count -gt 0) # If there are files
{
New-Item -Path "$Target\$year" -ItemType Directory -Force | Out-Null # Create Directory - Year
}
(1..12) | ForEach-Object{
$month = $_
$monthFiles = $files | Where-Object{ $_.CreationTime.Month -eq $month }
if($monthFiles.Count -gt 0) # If there are files
{
$dest = "$Target/$year/$month"
New-Item -Path $dest -ItemType Directory -Force | Out-Null # Create Directory - Month
$monthFiles | ForEach-Object{
Copy-Item -Path $_ -Destination $dest -Force
Write-Host "File: $_ , Year: $year, Month: $month, Destination: $dest/$($_ | Split-Path -Leaf)" #Remove this line in production
}
Compress-Archive -Path "$dest/*.*" -Destination "$dest/files-$year-$month.zip" -Force # Create Zip file
}
}
}
$_
it refers to object in current context, between(inside) curly braces.
for example Where-Object { $_.LastWriteTime.Year -eq $year}
in this case $_
is a file object, not int
value from ForEach-Object{ ..... }
context, previously I store the year value in $year
variable for use in Where-Object{ ..... }
context.
Same case for $month
variable.
REMEMBER to remove this line in the code
Write-Host "File: $_ , Year: $year, Month: $month, Destination: $dest/$($_ | Split-Path -Leaf)" #Remove this line in production
, this line can slow down the execution in case of having many files